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