xref: /dpdk/lib/pdcp/pdcp_crypto.c (revision 0da6d4013b788cb4f4e9561f271e8d6a97d4d726)
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