Branch data Line data Source code
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 : 0 : 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 : 0 : cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER; 23 : 0 : cap_idx.algo.cipher = c_xfrm->cipher.algo; 24 : : 25 : 0 : cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx); 26 [ # # ]: 0 : if (cap == NULL) 27 : : return -1; 28 : : 29 : 0 : ret = rte_cryptodev_sym_capability_check_cipher(cap, c_xfrm->cipher.key.length, 30 : 0 : c_xfrm->cipher.iv.length); 31 : : 32 : 0 : return ret; 33 : : } 34 : : 35 : : static int 36 : 0 : 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 : 0 : cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH; 43 : 0 : cap_idx.algo.auth = a_xfrm->auth.algo; 44 : : 45 : 0 : cap = rte_cryptodev_sym_capability_get(dev_id, &cap_idx); 46 [ # # ]: 0 : if (cap == NULL) 47 : : return -1; 48 : : 49 : 0 : ret = rte_cryptodev_sym_capability_check_auth(cap, a_xfrm->auth.key.length, 50 : 0 : a_xfrm->auth.digest_length, 51 : 0 : a_xfrm->auth.iv.length); 52 : : 53 : 0 : return ret; 54 : : } 55 : : 56 : : static int 57 : 0 : 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 [ # # ]: 0 : if (c_xfrm == NULL) 76 : : return -EINVAL; 77 : : 78 [ # # ]: 0 : if (conf->pdcp_xfrm.pkt_dir == RTE_SECURITY_PDCP_UPLINK) { 79 : : 80 : : /* With UPLINK, if auth is enabled, it should be before cipher */ 81 [ # # ]: 0 : if (a_xfrm != NULL && !is_auth_then_cipher) 82 : : return -EINVAL; 83 : : 84 : : /* With UPLINK, cipher operation must be encrypt */ 85 [ # # ]: 0 : 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 [ # # # # ]: 0 : if (a_xfrm != NULL && a_xfrm->auth.op != RTE_CRYPTO_AUTH_OP_GENERATE) 90 : : return -EINVAL; 91 : : 92 [ # # ]: 0 : } 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 [ # # ]: 0 : if (a_xfrm != NULL && is_auth_then_cipher) 96 : : return -EINVAL; 97 : : 98 : : /* With DOWNLINK, cipher operation must be decrypt */ 99 [ # # ]: 0 : 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 [ # # # # ]: 0 : 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 [ # # ]: 0 : if ((c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_NULL) && 111 [ # # ]: 0 : (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_AES_CTR) && 112 [ # # ]: 0 : (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_ZUC_EEA3) && 113 : : (c_xfrm->cipher.algo != RTE_CRYPTO_CIPHER_SNOW3G_UEA2)) 114 : : return -EINVAL; 115 : : 116 [ # # ]: 0 : 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 [ # # ]: 0 : if (cipher_iv_len != c_xfrm->cipher.iv.length) 122 : : return -EINVAL; 123 : : 124 [ # # ]: 0 : if (a_xfrm != NULL) { 125 [ # # ]: 0 : if ((a_xfrm->auth.algo != RTE_CRYPTO_AUTH_NULL) && 126 [ # # ]: 0 : (a_xfrm->auth.algo != RTE_CRYPTO_AUTH_AES_CMAC) && 127 [ # # ]: 0 : (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 [ # # ]: 0 : 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 [ # # ]: 0 : if (auth_digest_len != a_xfrm->auth.digest_length) 138 : : return -EINVAL; 139 : : 140 [ # # ]: 0 : 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 [ # # ]: 0 : if (a_xfrm->auth.iv.length != auth_iv_len) 147 : : return -EINVAL; 148 : : } 149 : : 150 [ # # ]: 0 : if (!rte_cryptodev_is_valid_dev(conf->dev_id)) 151 : : return -EINVAL; 152 : : 153 : 0 : ret = pdcp_crypto_caps_cipher_verify(conf->dev_id, c_xfrm); 154 [ # # ]: 0 : if (ret) 155 : : return -ENOTSUP; 156 : : 157 [ # # ]: 0 : if (a_xfrm != NULL) { 158 : 0 : ret = pdcp_crypto_caps_auth_verify(conf->dev_id, a_xfrm); 159 [ # # ]: 0 : if (ret) 160 : 0 : return -ENOTSUP; 161 : : } 162 : : 163 : : return 0; 164 : : } 165 : : 166 : : int 167 : 0 : 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 [ # # # # ]: 0 : if (entity == NULL || conf == NULL || conf->crypto_xfrm == NULL) 175 : : return -EINVAL; 176 : : 177 : : en_priv = entity_priv_get(entity); 178 : : 179 : 0 : en_priv->dev_id = conf->dev_id; 180 : : 181 [ # # ]: 0 : if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_CIPHER) { 182 : : c_xfrm = conf->crypto_xfrm; 183 : 0 : a_xfrm = conf->crypto_xfrm->next; 184 : : is_auth_then_cipher = false; 185 [ # # ]: 0 : } else if (conf->crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AUTH) { 186 : : a_xfrm = conf->crypto_xfrm; 187 : 0 : c_xfrm = conf->crypto_xfrm->next; 188 : : is_auth_then_cipher = true; 189 : : } else { 190 : : return -EINVAL; 191 : : } 192 : : 193 : 0 : ret = pdcp_crypto_xfrm_validate(conf, c_xfrm, a_xfrm, is_auth_then_cipher); 194 [ # # ]: 0 : if (ret) 195 : : return ret; 196 : : 197 [ # # ]: 0 : if (c_xfrm->cipher.algo == RTE_CRYPTO_CIPHER_NULL) 198 : 0 : c_xfrm->cipher.iv.offset = 0; 199 : : else 200 : 0 : c_xfrm->cipher.iv.offset = PDCP_IV_OFFSET; 201 : : 202 [ # # ]: 0 : if (a_xfrm != NULL) { 203 [ # # ]: 0 : if (a_xfrm->auth.algo == RTE_CRYPTO_AUTH_NULL) 204 : 0 : a_xfrm->auth.iv.offset = 0; 205 : : else 206 [ # # ]: 0 : if (c_xfrm->cipher.iv.offset) 207 : 0 : a_xfrm->auth.iv.offset = PDCP_IV_OFFSET + PDCP_IV_LEN; 208 : : else 209 : 0 : a_xfrm->auth.iv.offset = PDCP_IV_OFFSET; 210 : : } 211 : : 212 [ # # ]: 0 : if (conf->sess_mpool == NULL) 213 : : return -EINVAL; 214 : : 215 : 0 : en_priv->crypto_sess = rte_cryptodev_sym_session_create(conf->dev_id, conf->crypto_xfrm, 216 : : conf->sess_mpool); 217 [ # # ]: 0 : if (en_priv->crypto_sess == NULL) { 218 : : /* rte_errno is set as positive values of error codes */ 219 : 0 : return -rte_errno; 220 : : } 221 : : 222 : : rte_cryptodev_sym_session_opaque_data_set(en_priv->crypto_sess, (uint64_t)entity); 223 : : 224 : 0 : return 0; 225 : : } 226 : : 227 : : void 228 [ # # ]: 0 : 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 [ # # ]: 0 : if (en_priv->crypto_sess != NULL) { 235 : 0 : rte_cryptodev_sym_session_free(en_priv->dev_id, en_priv->crypto_sess); 236 : 0 : en_priv->crypto_sess = NULL; 237 : : } 238 : 0 : }