crypto/qat: add modular exponentiation
[dpdk.git] / drivers / crypto / qat / qat_asym.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Intel Corporation
3  */
4
5 #include <stdarg.h>
6
7 #include "qat_asym.h"
8 #include "icp_qat_fw_pke.h"
9 #include "icp_qat_fw.h"
10 #include "qat_pke_functionality_arrays.h"
11
12 #define qat_asym_sz_2param(arg) (arg, sizeof(arg)/sizeof(*arg))
13
14 static int qat_asym_get_sz_and_func_id(const uint32_t arr[][2],
15                 size_t arr_sz, size_t *size, uint32_t *func_id)
16 {
17         size_t i;
18
19         for (i = 0; i < arr_sz; i++) {
20                 if (*size <= arr[i][0]) {
21                         *size = arr[i][0];
22                         *func_id = arr[i][1];
23                         return 0;
24                 }
25         }
26         return -1;
27 }
28
29 static void qat_asym_build_req_tmpl(void *sess_private_data,
30                 struct rte_crypto_asym_xform *xform)
31 {
32
33         struct icp_qat_fw_pke_request *qat_req;
34         struct qat_asym_session *session = sess_private_data;
35
36         qat_req = &session->req_tmpl;
37         memset(qat_req, 0, sizeof(*qat_req));
38         qat_req->pke_hdr.service_type = ICP_QAT_FW_COMN_REQ_CPM_FW_PKE;
39
40         qat_req->pke_hdr.hdr_flags =
41                         ICP_QAT_FW_COMN_HDR_FLAGS_BUILD
42                         (ICP_QAT_FW_COMN_REQ_FLAG_SET);
43         qat_req->pke_hdr.comn_req_flags = 0;
44         qat_req->pke_hdr.resrvd1 = 0;
45         qat_req->pke_hdr.resrvd2 = 0;
46         qat_req->pke_hdr.kpt_mask = 0;
47         qat_req->pke_hdr.kpt_rn_mask = 0;
48         qat_req->pke_hdr.cd_pars.content_desc_addr = 0;
49         qat_req->pke_hdr.cd_pars.content_desc_resrvd = 0;
50         qat_req->resrvd1 = 0;
51         qat_req->resrvd2 = 0;
52         qat_req->next_req_adr = 0;
53
54         if (xform->xform_type == RTE_CRYPTO_ASYM_XFORM_MODEX) {
55                 qat_req->output_param_count = 1;
56                 qat_req->input_param_count = 3;
57         }
58 }
59
60 static size_t max_of(int n, ...)
61 {
62         va_list args;
63         size_t len = 0, num;
64         int i;
65
66         va_start(args, n);
67         len = va_arg(args, size_t);
68
69         for (i = 0; i < n - 1; i++) {
70                 num = va_arg(args, size_t);
71                 if (num > len)
72                         len = num;
73         }
74         va_end(args);
75
76         return len;
77 }
78
79 static void qat_clear_arrays(struct qat_asym_op_cookie *cookie,
80                 int in_count, int out_count, int in_size, int out_size)
81 {
82         int i;
83
84         for (i = 0; i < in_count; i++)
85                 memset(cookie->input_array[i], 0x0, in_size);
86         for (i = 0; i < out_count; i++)
87                 memset(cookie->output_array[i], 0x0, out_size);
88 }
89
90 static int qat_asym_check_nonzero(rte_crypto_param n)
91 {
92         if (n.length < 8) {
93                 /* Not a case for any cryptograpic function except for DH
94                  * generator which very often can be of one byte length
95                  */
96                 size_t i;
97
98                 if (n.data[n.length - 1] == 0x0) {
99                         for (i = 0; i < n.length - 1; i++)
100                                 if (n.data[i] != 0x0)
101                                         break;
102                         if (i == n.length - 1)
103                                 return QAT_ASYM_ERROR_INVALID_PARAM;
104                 }
105         } else if (*(uint64_t *)&n.data[
106                                 n.length - 8] == 0) {
107                 /* Very likely it is zeroed modulus */
108                 size_t i;
109
110                 for (i = 0; i < n.length - 8; i++)
111                         if (n.data[i] != 0x0)
112                                 break;
113                 if (i == n.length - 8)
114                         return QAT_ASYM_ERROR_INVALID_PARAM;
115         }
116
117         return 0;
118 }
119
120 int
121 qat_asym_build_request(void *in_op,
122                         uint8_t *out_msg,
123                         void *op_cookie,
124                         __rte_unused enum qat_device_gen qat_dev_gen)
125 {
126         struct qat_asym_session *ctx;
127         struct rte_crypto_op *op = (struct rte_crypto_op *)in_op;
128         struct rte_crypto_asym_op *asym_op = op->asym;
129         struct icp_qat_fw_pke_request *qat_req =
130                         (struct icp_qat_fw_pke_request *)out_msg;
131         struct qat_asym_op_cookie *cookie =
132                                 (struct qat_asym_op_cookie *)op_cookie;
133
134         uint64_t err = 0;
135         size_t alg_size;
136         size_t alg_size_in_bytes;
137         uint32_t func_id;
138
139         ctx = (struct qat_asym_session *)get_asym_session_private_data(
140                         op->asym->session, cryptodev_qat_asym_driver_id);
141         rte_mov64((uint8_t *)qat_req, (const uint8_t *)&(ctx->req_tmpl));
142         qat_req->pke_mid.opaque = (uint64_t)(uintptr_t)op;
143
144         qat_req->pke_mid.src_data_addr = cookie->input_addr;
145         qat_req->pke_mid.dest_data_addr = cookie->output_addr;
146
147         if (ctx->alg == QAT_PKE_MODEXP) {
148                 err = qat_asym_check_nonzero(ctx->sess_alg_params.mod_exp.n);
149                 if (err) {
150                         QAT_LOG(ERR, "Empty modulus, aborting this operation");
151                         goto error;
152                 }
153
154                 alg_size_in_bytes = max_of(3, asym_op->modex.base.length,
155                                ctx->sess_alg_params.mod_exp.e.length,
156                                ctx->sess_alg_params.mod_exp.n.length);
157                 alg_size = alg_size_in_bytes << 3;
158
159                 if (qat_asym_get_sz_and_func_id(MOD_EXP_SIZE,
160                                 sizeof(MOD_EXP_SIZE)/sizeof(*MOD_EXP_SIZE),
161                                 &alg_size, &func_id)) {
162                         err = QAT_ASYM_ERROR_INVALID_PARAM;
163                         goto error;
164                 }
165
166                 alg_size_in_bytes = alg_size >> 3;
167                 rte_memcpy(cookie->input_array[0] + alg_size_in_bytes -
168                         asym_op->modex.base.length
169                         , asym_op->modex.base.data,
170                         asym_op->modex.base.length);
171                 rte_memcpy(cookie->input_array[1] + alg_size_in_bytes -
172                         ctx->sess_alg_params.mod_exp.e.length
173                         , ctx->sess_alg_params.mod_exp.e.data,
174                         ctx->sess_alg_params.mod_exp.e.length);
175                 rte_memcpy(cookie->input_array[2]  + alg_size_in_bytes -
176                         ctx->sess_alg_params.mod_exp.n.length,
177                         ctx->sess_alg_params.mod_exp.n.data,
178                         ctx->sess_alg_params.mod_exp.n.length);
179                 cookie->alg_size = alg_size;
180                 qat_req->pke_hdr.cd_pars.func_id = func_id;
181 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
182                 QAT_DP_HEXDUMP_LOG(DEBUG, "base",
183                                 cookie->input_array[0],
184                                 alg_size_in_bytes);
185                 QAT_DP_HEXDUMP_LOG(DEBUG, "exponent",
186                                 cookie->input_array[1],
187                                 alg_size_in_bytes);
188                 QAT_DP_HEXDUMP_LOG(DEBUG, "modulus",
189                                 cookie->input_array[2],
190                                 alg_size_in_bytes);
191 #endif
192         }
193
194 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
195         QAT_DP_HEXDUMP_LOG(DEBUG, "qat_req:", qat_req,
196                         sizeof(struct icp_qat_fw_pke_request));
197 #endif
198         return 0;
199 error:
200         qat_req->output_param_count = 0;
201         qat_req->input_param_count = 0;
202         qat_req->pke_hdr.service_type = ICP_QAT_FW_COMN_REQ_NULL;
203         cookie->error |= err;
204
205         return 0;
206 }
207
208 void
209 qat_asym_process_response(void **op, uint8_t *resp,
210                 void *op_cookie)
211 {
212         struct qat_asym_session *ctx;
213         struct icp_qat_fw_pke_resp *resp_msg =
214                         (struct icp_qat_fw_pke_resp *)resp;
215         struct rte_crypto_op *rx_op = (struct rte_crypto_op *)(uintptr_t)
216                         (resp_msg->opaque);
217         struct rte_crypto_asym_op *asym_op = rx_op->asym;
218         struct qat_asym_op_cookie *cookie = op_cookie;
219         size_t alg_size, alg_size_in_bytes;
220
221         ctx = (struct qat_asym_session *)get_asym_session_private_data(
222                         rx_op->asym->session, cryptodev_qat_asym_driver_id);
223
224         *op = rx_op;
225         rx_op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
226
227         if (cookie->error) {
228                 cookie->error = 0;
229                 rx_op->status = RTE_CRYPTO_OP_STATUS_ERROR;
230                 QAT_DP_LOG(ERR, "Cookie status returned error");
231         } else {
232                 if (ICP_QAT_FW_PKE_RESP_PKE_STAT_GET(
233                         resp_msg->pke_resp_hdr.resp_status.pke_resp_flags)) {
234                         rx_op->status = RTE_CRYPTO_OP_STATUS_ERROR;
235                         QAT_DP_LOG(ERR, "Asymmetric response status returned error");
236                 }
237                 if (resp_msg->pke_resp_hdr.resp_status.comn_err_code) {
238                         rx_op->status = RTE_CRYPTO_OP_STATUS_ERROR;
239                         QAT_DP_LOG(ERR, "Asymmetric common status returned error");
240                 }
241         }
242
243         if (ctx->alg == QAT_PKE_MODEXP) {
244                 alg_size = cookie->alg_size;
245                 alg_size_in_bytes = alg_size >> 3;
246                 uint8_t *modexp_result = asym_op->modex.result.data;
247
248                 if (rx_op->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED) {
249                         rte_memcpy(modexp_result +
250                                 (asym_op->modex.result.length -
251                                         ctx->sess_alg_params.mod_exp.n.length),
252                                 cookie->output_array[0] + alg_size_in_bytes
253                                 - ctx->sess_alg_params.mod_exp.n.length,
254                                 ctx->sess_alg_params.mod_exp.n.length
255                                 );
256                         rx_op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
257 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
258                         QAT_DP_HEXDUMP_LOG(DEBUG, "modexp_result",
259                                         cookie->output_array[0],
260                                         alg_size_in_bytes);
261 #endif
262                 }
263                 qat_clear_arrays(cookie, 3, 1, alg_size_in_bytes,
264                                 alg_size_in_bytes);
265         }
266
267 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG
268         QAT_DP_HEXDUMP_LOG(DEBUG, "resp_msg:", resp_msg,
269                         sizeof(struct icp_qat_fw_pke_resp));
270 #endif
271 }
272
273 int
274 qat_asym_session_configure(struct rte_cryptodev *dev,
275                 struct rte_crypto_asym_xform *xform,
276                 struct rte_cryptodev_asym_session *sess,
277                 struct rte_mempool *mempool)
278 {
279         int err = 0;
280         void *sess_private_data;
281         struct qat_asym_session *session;
282
283         if (rte_mempool_get(mempool, &sess_private_data)) {
284                 QAT_LOG(ERR,
285                         "Couldn't get object from session mempool");
286                 return -ENOMEM;
287         }
288
289         session = sess_private_data;
290         if (xform->xform_type == RTE_CRYPTO_ASYM_XFORM_MODEX) {
291                 session->sess_alg_params.mod_exp.e = xform->modex.exponent;
292                 session->sess_alg_params.mod_exp.n = xform->modex.modulus;
293                 session->alg = QAT_PKE_MODEXP;
294
295                 if (xform->modex.exponent.length == 0 ||
296                                 xform->modex.modulus.length == 0) {
297                         QAT_LOG(ERR, "Invalid mod exp input parameter");
298                         err = -EINVAL;
299                         goto error;
300                 }
301         } else {
302                 QAT_LOG(ERR, "Invalid asymmetric crypto xform");
303                 err = -EINVAL;
304                 goto error;
305         }
306         qat_asym_build_req_tmpl(sess_private_data, xform);
307         set_asym_session_private_data(sess, dev->driver_id,
308                 sess_private_data);
309
310         return 0;
311 error:
312         rte_mempool_put(mempool, sess_private_data);
313         return err;
314 }
315
316 unsigned int qat_asym_session_get_private_size(
317                 struct rte_cryptodev *dev __rte_unused)
318 {
319         return RTE_ALIGN_CEIL(sizeof(struct qat_asym_session), 8);
320 }
321
322 void
323 qat_asym_session_clear(struct rte_cryptodev *dev,
324                 struct rte_cryptodev_asym_session *sess)
325 {
326         uint8_t index = dev->driver_id;
327         void *sess_priv = get_asym_session_private_data(sess, index);
328         struct qat_asym_session *s = (struct qat_asym_session *)sess_priv;
329
330         if (sess_priv) {
331                 memset(s, 0, qat_asym_session_get_private_size(dev));
332                 struct rte_mempool *sess_mp = rte_mempool_from_obj(sess_priv);
333
334                 set_asym_session_private_data(sess, index, NULL);
335                 rte_mempool_put(sess_mp, sess_priv);
336         }
337 }