1a702bd09SAnoob Joseph /* SPDX-License-Identifier: BSD-3-Clause
2a702bd09SAnoob Joseph * Copyright(C) 2023 Marvell.
3a702bd09SAnoob Joseph */
4a702bd09SAnoob Joseph
5*0da6d401SAnoob Joseph #include <rte_crypto.h>
6*0da6d401SAnoob Joseph #include <rte_crypto_sym.h>
7*0da6d401SAnoob Joseph #include <rte_cryptodev.h>
8*0da6d401SAnoob Joseph #include <rte_errno.h>
9a702bd09SAnoob Joseph #include <rte_pdcp.h>
10*0da6d401SAnoob Joseph #include <rte_pdcp_hdr.h>
11a702bd09SAnoob Joseph
12a702bd09SAnoob Joseph #include "pdcp_crypto.h"
13*0da6d401SAnoob Joseph #include "pdcp_entity.h"
14*0da6d401SAnoob Joseph
15*0da6d401SAnoob Joseph static int
pdcp_crypto_caps_cipher_verify(uint8_t dev_id,const struct rte_crypto_sym_xform * c_xfrm)16*0da6d401SAnoob Joseph pdcp_crypto_caps_cipher_verify(uint8_t dev_id, const struct rte_crypto_sym_xform *c_xfrm)
17*0da6d401SAnoob Joseph {
18*0da6d401SAnoob Joseph const struct rte_cryptodev_symmetric_capability *cap;
19*0da6d401SAnoob Joseph struct rte_cryptodev_sym_capability_idx cap_idx;
20*0da6d401SAnoob Joseph int ret;
21*0da6d401SAnoob Joseph
22*0da6d401SAnoob Joseph cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
23*0da6d401SAnoob Joseph cap_idx.algo.cipher = c_xfrm->cipher.algo;
24*0da6d401SAnoob Joseph
25*0da6d401SAnoob Joseph cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx);
26*0da6d401SAnoob Joseph if (cap == NULL)
27*0da6d401SAnoob Joseph return -1;
28*0da6d401SAnoob Joseph
29*0da6d401SAnoob Joseph ret = rte_cryptodev_sym_capability_check_cipher(cap, c_xfrm->cipher.key.length,
30*0da6d401SAnoob Joseph c_xfrm->cipher.iv.length);
31*0da6d401SAnoob Joseph
32*0da6d401SAnoob Joseph return ret;
33*0da6d401SAnoob Joseph }
34*0da6d401SAnoob Joseph
35*0da6d401SAnoob Joseph static int
pdcp_crypto_caps_auth_verify(uint8_t dev_id,const struct rte_crypto_sym_xform * a_xfrm)36*0da6d401SAnoob Joseph pdcp_crypto_caps_auth_verify(uint8_t dev_id, const struct rte_crypto_sym_xform *a_xfrm)
37*0da6d401SAnoob Joseph {
38*0da6d401SAnoob Joseph const struct rte_cryptodev_symmetric_capability *cap;
39*0da6d401SAnoob Joseph struct rte_cryptodev_sym_capability_idx cap_idx;
40*0da6d401SAnoob Joseph int ret;
41*0da6d401SAnoob Joseph
42*0da6d401SAnoob Joseph cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
43*0da6d401SAnoob Joseph cap_idx.algo.auth = a_xfrm->auth.algo;
44*0da6d401SAnoob Joseph
45*0da6d401SAnoob Joseph cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx);
46*0da6d401SAnoob Joseph if (cap == NULL)
47*0da6d401SAnoob Joseph return -1;
48*0da6d401SAnoob Joseph
49*0da6d401SAnoob Joseph ret = rte_cryptodev_sym_capability_check_auth(cap, a_xfrm->auth.key.length,
50*0da6d401SAnoob Joseph a_xfrm->auth.digest_length,
51*0da6d401SAnoob Joseph a_xfrm->auth.iv.length);
52*0da6d401SAnoob Joseph
53*0da6d401SAnoob Joseph return ret;
54*0da6d401SAnoob Joseph }
55*0da6d401SAnoob Joseph
56*0da6d401SAnoob Joseph static int
pdcp_crypto_xfrm_validate(const struct rte_pdcp_entity_conf * conf,const struct rte_crypto_sym_xform * c_xfrm,const struct rte_crypto_sym_xform * a_xfrm,bool is_auth_then_cipher)57*0da6d401SAnoob Joseph pdcp_crypto_xfrm_validate(const struct rte_pdcp_entity_conf *conf,
58*0da6d401SAnoob Joseph const struct rte_crypto_sym_xform *c_xfrm,
59*0da6d401SAnoob Joseph const struct rte_crypto_sym_xform *a_xfrm,
60*0da6d401SAnoob Joseph bool is_auth_then_cipher)
61*0da6d401SAnoob Joseph {
62*0da6d401SAnoob Joseph uint16_t cipher_iv_len, auth_digest_len, auth_iv_len;
63*0da6d401SAnoob Joseph int ret;
64*0da6d401SAnoob Joseph
65*0da6d401SAnoob Joseph /*
66*0da6d401SAnoob Joseph * Uplink means PDCP entity is configured for transmit. Downlink means PDCP entity is
67*0da6d401SAnoob Joseph * configured for receive. When integrity protection is enabled, PDCP always performs
68*0da6d401SAnoob Joseph * digest-encrypted or auth-gen-encrypt for uplink (and decrypt-auth-verify for downlink).
69*0da6d401SAnoob Joseph * So for uplink, crypto chain would be auth-cipher while for downlink it would be
70*0da6d401SAnoob Joseph * cipher-auth.
71*0da6d401SAnoob Joseph *
72*0da6d401SAnoob Joseph * When integrity protection is not required, xform would be cipher only.
73*0da6d401SAnoob Joseph */
74*0da6d401SAnoob Joseph
75*0da6d401SAnoob Joseph if (c_xfrm == NULL)
76*0da6d401SAnoob Joseph return -EINVAL;
77*0da6d401SAnoob Joseph
78*0da6d401SAnoob Joseph if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK) {
79*0da6d401SAnoob Joseph
80*0da6d401SAnoob Joseph /* With UPLINK, if auth is enabled, it should be before cipher */
81*0da6d401SAnoob Joseph if (a_xfrm != NULL && !is_auth_then_cipher)
82*0da6d401SAnoob Joseph return -EINVAL;
83*0da6d401SAnoob Joseph
84*0da6d401SAnoob Joseph /* With UPLINK, cipher operation must be encrypt */
85*0da6d401SAnoob Joseph if (c_xfrm->cipher.op != RTE_CRYPTO_CIPHER_OP_ENCRYPT)
86*0da6d401SAnoob Joseph return -EINVAL;
87*0da6d401SAnoob Joseph
88*0da6d401SAnoob Joseph /* With UPLINK, auth operation (if present) must be generate */
89*0da6d401SAnoob Joseph if (a_xfrm != NULL && a_xfrm->auth.op != RTE_CRYPTO_AUTH_OP_GENERATE)
90*0da6d401SAnoob Joseph return -EINVAL;
91*0da6d401SAnoob Joseph
92*0da6d401SAnoob Joseph } else if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_DOWNLINK) {
93*0da6d401SAnoob Joseph
94*0da6d401SAnoob Joseph /* With DOWNLINK, if auth is enabled, it should be after cipher */
95*0da6d401SAnoob Joseph if (a_xfrm != NULL && is_auth_then_cipher)
96*0da6d401SAnoob Joseph return -EINVAL;
97*0da6d401SAnoob Joseph
98*0da6d401SAnoob Joseph /* With DOWNLINK, cipher operation must be decrypt */
99*0da6d401SAnoob Joseph if (c_xfrm->cipher.op != RTE_CRYPTO_CIPHER_OP_DECRYPT)
100*0da6d401SAnoob Joseph return -EINVAL;
101*0da6d401SAnoob Joseph
102*0da6d401SAnoob Joseph /* With DOWNLINK, auth operation (if present) must be verify */
103*0da6d401SAnoob Joseph if (a_xfrm != NULL && a_xfrm->auth.op != RTE_CRYPTO_AUTH_OP_VERIFY)
104*0da6d401SAnoob Joseph return -EINVAL;
105*0da6d401SAnoob Joseph
106*0da6d401SAnoob Joseph } else {
107*0da6d401SAnoob Joseph return -EINVAL;
108*0da6d401SAnoob Joseph }
109*0da6d401SAnoob Joseph
110*0da6d401SAnoob Joseph if ((c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_NULL) &&
111*0da6d401SAnoob Joseph (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_AES_CTR) &&
112*0da6d401SAnoob Joseph (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_ZUC_EEA3) &&
113*0da6d401SAnoob Joseph (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_SNOW3G_UEA2))
114*0da6d401SAnoob Joseph return -EINVAL;
115*0da6d401SAnoob Joseph
116*0da6d401SAnoob Joseph if (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_NULL)
117*0da6d401SAnoob Joseph cipher_iv_len = 0;
118*0da6d401SAnoob Joseph else
119*0da6d401SAnoob Joseph cipher_iv_len = PDCP_IV_LEN;
120*0da6d401SAnoob Joseph
121*0da6d401SAnoob Joseph if (cipher_iv_len != c_xfrm->cipher.iv.length)
122*0da6d401SAnoob Joseph return -EINVAL;
123*0da6d401SAnoob Joseph
124*0da6d401SAnoob Joseph if (a_xfrm != NULL) {
125*0da6d401SAnoob Joseph if ((a_xfrm->auth.algo != RTE_CRYPTO_AUTH_NULL) &&
126*0da6d401SAnoob Joseph (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_AES_CMAC) &&
127*0da6d401SAnoob Joseph (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_ZUC_EIA3) &&
128*0da6d401SAnoob Joseph (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_SNOW3G_UIA2))
129*0da6d401SAnoob Joseph return -EINVAL;
130*0da6d401SAnoob Joseph
131*0da6d401SAnoob Joseph /* For AUTH NULL, lib PDCP would add 4 byte 0s */
132*0da6d401SAnoob Joseph if (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL)
133*0da6d401SAnoob Joseph auth_digest_len = 0;
134*0da6d401SAnoob Joseph else
135*0da6d401SAnoob Joseph auth_digest_len = RTE_PDCP_MAC_I_LEN;
136*0da6d401SAnoob Joseph
137*0da6d401SAnoob Joseph if (auth_digest_len != a_xfrm->auth.digest_length)
138*0da6d401SAnoob Joseph return -EINVAL;
139*0da6d401SAnoob Joseph
140*0da6d401SAnoob Joseph if ((a_xfrm->auth.algo == RTE_CRYPTO_AUTH_ZUC_EIA3) ||
141*0da6d401SAnoob Joseph (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_SNOW3G_UIA2))
142*0da6d401SAnoob Joseph auth_iv_len = PDCP_IV_LEN;
143*0da6d401SAnoob Joseph else
144*0da6d401SAnoob Joseph auth_iv_len = 0;
145*0da6d401SAnoob Joseph
146*0da6d401SAnoob Joseph if (a_xfrm->auth.iv.length != auth_iv_len)
147*0da6d401SAnoob Joseph return -EINVAL;
148*0da6d401SAnoob Joseph }
149*0da6d401SAnoob Joseph
150*0da6d401SAnoob Joseph if (!rte_cryptodev_is_valid_dev(conf->dev_id))
151*0da6d401SAnoob Joseph return -EINVAL;
152*0da6d401SAnoob Joseph
153*0da6d401SAnoob Joseph ret = pdcp_crypto_caps_cipher_verify(conf->dev_id, c_xfrm);
154*0da6d401SAnoob Joseph if (ret)
155*0da6d401SAnoob Joseph return -ENOTSUP;
156*0da6d401SAnoob Joseph
157*0da6d401SAnoob Joseph if (a_xfrm != NULL) {
158*0da6d401SAnoob Joseph ret = pdcp_crypto_caps_auth_verify(conf->dev_id, a_xfrm);
159*0da6d401SAnoob Joseph if (ret)
160*0da6d401SAnoob Joseph return -ENOTSUP;
161*0da6d401SAnoob Joseph }
162*0da6d401SAnoob Joseph
163*0da6d401SAnoob Joseph return 0;
164*0da6d401SAnoob Joseph }
165a702bd09SAnoob Joseph
166a702bd09SAnoob Joseph int
pdcp_crypto_sess_create(struct rte_pdcp_entity * entity,const struct rte_pdcp_entity_conf * conf)167a702bd09SAnoob Joseph pdcp_crypto_sess_create(struct rte_pdcp_entity *entity, const struct rte_pdcp_entity_conf *conf)
168a702bd09SAnoob Joseph {
169*0da6d401SAnoob Joseph struct rte_crypto_sym_xform *c_xfrm, *a_xfrm;
170*0da6d401SAnoob Joseph struct entity_priv *en_priv;
171*0da6d401SAnoob Joseph bool is_auth_then_cipher;
172*0da6d401SAnoob Joseph int ret;
173*0da6d401SAnoob Joseph
174*0da6d401SAnoob Joseph if (entity == NULL || conf == NULL || conf->crypto_xfrm == NULL)
175*0da6d401SAnoob Joseph return -EINVAL;
176*0da6d401SAnoob Joseph
177*0da6d401SAnoob Joseph en_priv = entity_priv_get(entity);
178*0da6d401SAnoob Joseph
179*0da6d401SAnoob Joseph en_priv->dev_id = conf->dev_id;
180*0da6d401SAnoob Joseph
181*0da6d401SAnoob Joseph if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
182*0da6d401SAnoob Joseph c_xfrm = conf->crypto_xfrm;
183*0da6d401SAnoob Joseph a_xfrm = conf->crypto_xfrm->next;
184*0da6d401SAnoob Joseph is_auth_then_cipher = false;
185*0da6d401SAnoob Joseph } else if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
186*0da6d401SAnoob Joseph a_xfrm = conf->crypto_xfrm;
187*0da6d401SAnoob Joseph c_xfrm = conf->crypto_xfrm->next;
188*0da6d401SAnoob Joseph is_auth_then_cipher = true;
189*0da6d401SAnoob Joseph } else {
190*0da6d401SAnoob Joseph return -EINVAL;
191*0da6d401SAnoob Joseph }
192*0da6d401SAnoob Joseph
193*0da6d401SAnoob Joseph ret = pdcp_crypto_xfrm_validate(conf, c_xfrm, a_xfrm, is_auth_then_cipher);
194*0da6d401SAnoob Joseph if (ret)
195*0da6d401SAnoob Joseph return ret;
196*0da6d401SAnoob Joseph
197*0da6d401SAnoob Joseph if (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_NULL)
198*0da6d401SAnoob Joseph c_xfrm->cipher.iv.offset = 0;
199*0da6d401SAnoob Joseph else
200*0da6d401SAnoob Joseph c_xfrm->cipher.iv.offset = PDCP_IV_OFFSET;
201*0da6d401SAnoob Joseph
202*0da6d401SAnoob Joseph if (a_xfrm != NULL) {
203*0da6d401SAnoob Joseph if (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL)
204*0da6d401SAnoob Joseph a_xfrm->auth.iv.offset = 0;
205*0da6d401SAnoob Joseph else
206*0da6d401SAnoob Joseph if (c_xfrm->cipher.iv.offset)
207*0da6d401SAnoob Joseph a_xfrm->auth.iv.offset = PDCP_IV_OFFSET + PDCP_IV_LEN;
208*0da6d401SAnoob Joseph else
209*0da6d401SAnoob Joseph a_xfrm->auth.iv.offset = PDCP_IV_OFFSET;
210*0da6d401SAnoob Joseph }
211*0da6d401SAnoob Joseph
212*0da6d401SAnoob Joseph if (conf->sess_mpool == NULL)
213*0da6d401SAnoob Joseph return -EINVAL;
214*0da6d401SAnoob Joseph
215*0da6d401SAnoob Joseph en_priv->crypto_sess = rte_cryptodev_sym_session_create(conf->dev_id, conf->crypto_xfrm,
216*0da6d401SAnoob Joseph conf->sess_mpool);
217*0da6d401SAnoob Joseph if (en_priv->crypto_sess == NULL) {
218*0da6d401SAnoob Joseph /* rte_errno is set as positive values of error codes */
219*0da6d401SAnoob Joseph return -rte_errno;
220*0da6d401SAnoob Joseph }
221*0da6d401SAnoob Joseph
222*0da6d401SAnoob Joseph rte_cryptodev_sym_session_opaque_data_set(en_priv->crypto_sess, (uint64_t)entity);
223*0da6d401SAnoob Joseph
224a702bd09SAnoob Joseph return 0;
225a702bd09SAnoob Joseph }
226a702bd09SAnoob Joseph
227a702bd09SAnoob Joseph void
pdcp_crypto_sess_destroy(struct rte_pdcp_entity * entity)228a702bd09SAnoob Joseph pdcp_crypto_sess_destroy(struct rte_pdcp_entity *entity)
229a702bd09SAnoob Joseph {
230*0da6d401SAnoob Joseph struct entity_priv *en_priv;
231*0da6d401SAnoob Joseph
232*0da6d401SAnoob Joseph en_priv = entity_priv_get(entity);
233*0da6d401SAnoob Joseph
234*0da6d401SAnoob Joseph if (en_priv->crypto_sess != NULL) {
235*0da6d401SAnoob Joseph rte_cryptodev_sym_session_free(en_priv->dev_id, en_priv->crypto_sess);
236*0da6d401SAnoob Joseph en_priv->crypto_sess = NULL;
237*0da6d401SAnoob Joseph }
238a702bd09SAnoob Joseph }
239