1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2021 Marvell. 3 */ 4 5 #include <rte_common.h> 6 #include <rte_cryptodev.h> 7 #include <rte_esp.h> 8 #include <rte_ip.h> 9 #include <rte_security.h> 10 #include <rte_udp.h> 11 12 #include "test.h" 13 #include "test_cryptodev_security_ipsec.h" 14 15 #define IV_LEN_MAX 16 16 17 extern struct ipsec_test_data pkt_aes_256_gcm; 18 19 int 20 test_ipsec_sec_caps_verify(struct rte_security_ipsec_xform *ipsec_xform, 21 const struct rte_security_capability *sec_cap, 22 bool silent) 23 { 24 /* Verify security capabilities */ 25 26 if (ipsec_xform->options.esn == 1 && sec_cap->ipsec.options.esn == 0) { 27 if (!silent) 28 RTE_LOG(INFO, USER1, "ESN is not supported\n"); 29 return -ENOTSUP; 30 } 31 32 if (ipsec_xform->options.udp_encap == 1 && 33 sec_cap->ipsec.options.udp_encap == 0) { 34 if (!silent) 35 RTE_LOG(INFO, USER1, "UDP encapsulation is not supported\n"); 36 return -ENOTSUP; 37 } 38 39 if (ipsec_xform->options.copy_dscp == 1 && 40 sec_cap->ipsec.options.copy_dscp == 0) { 41 if (!silent) 42 RTE_LOG(INFO, USER1, "Copy DSCP is not supported\n"); 43 return -ENOTSUP; 44 } 45 46 if (ipsec_xform->options.copy_flabel == 1 && 47 sec_cap->ipsec.options.copy_flabel == 0) { 48 if (!silent) 49 RTE_LOG(INFO, USER1, "Copy Flow Label is not supported\n"); 50 return -ENOTSUP; 51 } 52 53 if (ipsec_xform->options.copy_df == 1 && 54 sec_cap->ipsec.options.copy_df == 0) { 55 if (!silent) 56 RTE_LOG(INFO, USER1, "Copy DP bit is not supported\n"); 57 return -ENOTSUP; 58 } 59 60 if (ipsec_xform->options.dec_ttl == 1 && 61 sec_cap->ipsec.options.dec_ttl == 0) { 62 if (!silent) 63 RTE_LOG(INFO, USER1, "Decrement TTL is not supported\n"); 64 return -ENOTSUP; 65 } 66 67 if (ipsec_xform->options.ecn == 1 && sec_cap->ipsec.options.ecn == 0) { 68 if (!silent) 69 RTE_LOG(INFO, USER1, "ECN is not supported\n"); 70 return -ENOTSUP; 71 } 72 73 if (ipsec_xform->options.stats == 1 && 74 sec_cap->ipsec.options.stats == 0) { 75 if (!silent) 76 RTE_LOG(INFO, USER1, "Stats is not supported\n"); 77 return -ENOTSUP; 78 } 79 80 if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) && 81 (ipsec_xform->options.iv_gen_disable == 1) && 82 (sec_cap->ipsec.options.iv_gen_disable != 1)) { 83 if (!silent) 84 RTE_LOG(INFO, USER1, 85 "Application provided IV is not supported\n"); 86 return -ENOTSUP; 87 } 88 89 if ((ipsec_xform->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) && 90 (ipsec_xform->options.tunnel_hdr_verify > 91 sec_cap->ipsec.options.tunnel_hdr_verify)) { 92 if (!silent) 93 RTE_LOG(INFO, USER1, 94 "Tunnel header verify is not supported\n"); 95 return -ENOTSUP; 96 } 97 98 return 0; 99 } 100 101 int 102 test_ipsec_crypto_caps_aead_verify( 103 const struct rte_security_capability *sec_cap, 104 struct rte_crypto_sym_xform *aead) 105 { 106 const struct rte_cryptodev_symmetric_capability *sym_cap; 107 const struct rte_cryptodev_capabilities *crypto_cap; 108 int j = 0; 109 110 while ((crypto_cap = &sec_cap->crypto_capabilities[j++])->op != 111 RTE_CRYPTO_OP_TYPE_UNDEFINED) { 112 if (crypto_cap->op == RTE_CRYPTO_OP_TYPE_SYMMETRIC && 113 crypto_cap->sym.xform_type == aead->type && 114 crypto_cap->sym.aead.algo == aead->aead.algo) { 115 sym_cap = &crypto_cap->sym; 116 if (rte_cryptodev_sym_capability_check_aead(sym_cap, 117 aead->aead.key.length, 118 aead->aead.digest_length, 119 aead->aead.aad_length, 120 aead->aead.iv.length) == 0) 121 return 0; 122 } 123 } 124 125 return -ENOTSUP; 126 } 127 128 void 129 test_ipsec_td_in_from_out(const struct ipsec_test_data *td_out, 130 struct ipsec_test_data *td_in) 131 { 132 memcpy(td_in, td_out, sizeof(*td_in)); 133 134 /* Populate output text of td_in with input text of td_out */ 135 memcpy(td_in->output_text.data, td_out->input_text.data, 136 td_out->input_text.len); 137 td_in->output_text.len = td_out->input_text.len; 138 139 /* Populate input text of td_in with output text of td_out */ 140 memcpy(td_in->input_text.data, td_out->output_text.data, 141 td_out->output_text.len); 142 td_in->input_text.len = td_out->output_text.len; 143 144 td_in->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS; 145 146 if (td_in->aead) { 147 td_in->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT; 148 } else { 149 td_in->xform.chain.auth.auth.op = RTE_CRYPTO_AUTH_OP_VERIFY; 150 td_in->xform.chain.cipher.cipher.op = 151 RTE_CRYPTO_CIPHER_OP_DECRYPT; 152 } 153 } 154 155 void 156 test_ipsec_td_prepare(const struct crypto_param *param1, 157 const struct crypto_param *param2, 158 const struct ipsec_test_flags *flags, 159 struct ipsec_test_data *td_array, 160 int nb_td) 161 162 { 163 struct ipsec_test_data *td; 164 int i; 165 166 memset(td_array, 0, nb_td * sizeof(*td)); 167 168 for (i = 0; i < nb_td; i++) { 169 td = &td_array[i]; 170 /* Copy template for packet & key fields */ 171 memcpy(td, &pkt_aes_256_gcm, sizeof(*td)); 172 173 /* Override fields based on param */ 174 175 if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) 176 td->aead = true; 177 else 178 td->aead = false; 179 180 td->xform.aead.aead.algo = param1->alg.aead; 181 td->xform.aead.aead.key.length = param1->key_length; 182 183 if (flags->iv_gen) 184 td->ipsec_xform.options.iv_gen_disable = 0; 185 186 if (flags->sa_expiry_pkts_soft) 187 td->ipsec_xform.life.packets_soft_limit = 188 IPSEC_TEST_PACKETS_MAX - 1; 189 } 190 191 RTE_SET_USED(param2); 192 } 193 194 void 195 test_ipsec_td_update(struct ipsec_test_data td_inb[], 196 const struct ipsec_test_data td_outb[], 197 int nb_td, 198 const struct ipsec_test_flags *flags) 199 { 200 int i; 201 202 for (i = 0; i < nb_td; i++) { 203 memcpy(td_inb[i].output_text.data, td_outb[i].input_text.data, 204 td_outb[i].input_text.len); 205 td_inb[i].output_text.len = td_outb->input_text.len; 206 207 if (flags->icv_corrupt) { 208 int icv_pos = td_inb[i].input_text.len - 4; 209 td_inb[i].input_text.data[icv_pos] += 1; 210 } 211 212 if (flags->sa_expiry_pkts_hard) 213 td_inb[i].ipsec_xform.life.packets_hard_limit = 214 IPSEC_TEST_PACKETS_MAX - 1; 215 216 if (flags->udp_encap) 217 td_inb[i].ipsec_xform.options.udp_encap = 1; 218 219 td_inb[i].ipsec_xform.options.tunnel_hdr_verify = 220 flags->tunnel_hdr_verify; 221 222 /* Clear outbound specific flags */ 223 td_inb[i].ipsec_xform.options.iv_gen_disable = 0; 224 } 225 } 226 227 void 228 test_ipsec_display_alg(const struct crypto_param *param1, 229 const struct crypto_param *param2) 230 { 231 if (param1->type == RTE_CRYPTO_SYM_XFORM_AEAD) 232 printf("\t%s [%d]\n", 233 rte_crypto_aead_algorithm_strings[param1->alg.aead], 234 param1->key_length); 235 236 RTE_SET_USED(param2); 237 } 238 239 static int 240 test_ipsec_tunnel_hdr_len_get(const struct ipsec_test_data *td) 241 { 242 int len = 0; 243 244 if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 245 if (td->ipsec_xform.mode == RTE_SECURITY_IPSEC_SA_MODE_TUNNEL) { 246 if (td->ipsec_xform.tunnel.type == 247 RTE_SECURITY_IPSEC_TUNNEL_IPV4) 248 len += sizeof(struct rte_ipv4_hdr); 249 else 250 len += sizeof(struct rte_ipv6_hdr); 251 } 252 } 253 254 return len; 255 } 256 257 static int 258 test_ipsec_iv_verify_push(struct rte_mbuf *m, const struct ipsec_test_data *td) 259 { 260 static uint8_t iv_queue[IV_LEN_MAX * IPSEC_TEST_PACKETS_MAX]; 261 uint8_t *iv_tmp, *output_text = rte_pktmbuf_mtod(m, uint8_t *); 262 int i, iv_pos, iv_len; 263 static int index; 264 265 if (td->aead) 266 iv_len = td->xform.aead.aead.iv.length - td->salt.len; 267 else 268 iv_len = td->xform.chain.cipher.cipher.iv.length; 269 270 iv_pos = test_ipsec_tunnel_hdr_len_get(td) + sizeof(struct rte_esp_hdr); 271 output_text += iv_pos; 272 273 TEST_ASSERT(iv_len <= IV_LEN_MAX, "IV length greater than supported"); 274 275 /* Compare against previous values */ 276 for (i = 0; i < index; i++) { 277 iv_tmp = &iv_queue[i * IV_LEN_MAX]; 278 279 if (memcmp(output_text, iv_tmp, iv_len) == 0) { 280 printf("IV repeated"); 281 return TEST_FAILED; 282 } 283 } 284 285 /* Save IV for future comparisons */ 286 287 iv_tmp = &iv_queue[index * IV_LEN_MAX]; 288 memcpy(iv_tmp, output_text, iv_len); 289 index++; 290 291 if (index == IPSEC_TEST_PACKETS_MAX) 292 index = 0; 293 294 return TEST_SUCCESS; 295 } 296 297 static int 298 test_ipsec_td_verify(struct rte_mbuf *m, const struct ipsec_test_data *td, 299 bool silent, const struct ipsec_test_flags *flags) 300 { 301 uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *); 302 uint32_t skip, len = rte_pktmbuf_pkt_len(m); 303 304 /* For tests with status as error for test success, skip verification */ 305 if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && 306 (flags->icv_corrupt || 307 flags->sa_expiry_pkts_hard || 308 flags->tunnel_hdr_verify)) 309 return TEST_SUCCESS; 310 311 if (td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS && 312 flags->udp_encap) { 313 const struct rte_ipv4_hdr *iph4; 314 const struct rte_ipv6_hdr *iph6; 315 316 if (td->ipsec_xform.tunnel.type == 317 RTE_SECURITY_IPSEC_TUNNEL_IPV4) { 318 iph4 = (const struct rte_ipv4_hdr *)output_text; 319 if (iph4->next_proto_id != IPPROTO_UDP) { 320 printf("UDP header is not found\n"); 321 return TEST_FAILED; 322 } 323 } else { 324 iph6 = (const struct rte_ipv6_hdr *)output_text; 325 if (iph6->proto != IPPROTO_UDP) { 326 printf("UDP header is not found\n"); 327 return TEST_FAILED; 328 } 329 } 330 331 len -= sizeof(struct rte_udp_hdr); 332 output_text += sizeof(struct rte_udp_hdr); 333 } 334 335 if (len != td->output_text.len) { 336 printf("Output length (%d) not matching with expected (%d)\n", 337 len, td->output_text.len); 338 return TEST_FAILED; 339 } 340 341 skip = test_ipsec_tunnel_hdr_len_get(td); 342 343 len -= skip; 344 output_text += skip; 345 346 if (memcmp(output_text, td->output_text.data + skip, len)) { 347 if (silent) 348 return TEST_FAILED; 349 350 printf("TestCase %s line %d: %s\n", __func__, __LINE__, 351 "output text not as expected\n"); 352 353 rte_hexdump(stdout, "expected", td->output_text.data + skip, 354 len); 355 rte_hexdump(stdout, "actual", output_text, len); 356 return TEST_FAILED; 357 } 358 359 return TEST_SUCCESS; 360 } 361 362 static int 363 test_ipsec_res_d_prepare(struct rte_mbuf *m, const struct ipsec_test_data *td, 364 struct ipsec_test_data *res_d) 365 { 366 uint8_t *output_text = rte_pktmbuf_mtod(m, uint8_t *); 367 uint32_t len = rte_pktmbuf_pkt_len(m); 368 369 memcpy(res_d, td, sizeof(*res_d)); 370 memcpy(res_d->input_text.data, output_text, len); 371 res_d->input_text.len = len; 372 373 res_d->ipsec_xform.direction = RTE_SECURITY_IPSEC_SA_DIR_INGRESS; 374 if (res_d->aead) { 375 res_d->xform.aead.aead.op = RTE_CRYPTO_AEAD_OP_DECRYPT; 376 } else { 377 printf("Only AEAD supported\n"); 378 return TEST_SKIPPED; 379 } 380 381 return TEST_SUCCESS; 382 } 383 384 int 385 test_ipsec_post_process(struct rte_mbuf *m, const struct ipsec_test_data *td, 386 struct ipsec_test_data *res_d, bool silent, 387 const struct ipsec_test_flags *flags) 388 { 389 int ret; 390 391 if (flags->iv_gen && 392 td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { 393 ret = test_ipsec_iv_verify_push(m, td); 394 if (ret != TEST_SUCCESS) 395 return ret; 396 } 397 398 /* 399 * In case of known vector tests & all inbound tests, res_d provided 400 * would be NULL and output data need to be validated against expected. 401 * For inbound, output_text would be plain packet and for outbound 402 * output_text would IPsec packet. Validate by comparing against 403 * known vectors. 404 * 405 * In case of combined mode tests, the output_text from outbound 406 * operation (ie, IPsec packet) would need to be inbound processed to 407 * obtain the plain text. Copy output_text to result data, 'res_d', so 408 * that inbound processing can be done. 409 */ 410 411 if (res_d == NULL) 412 return test_ipsec_td_verify(m, td, silent, flags); 413 else 414 return test_ipsec_res_d_prepare(m, td, res_d); 415 } 416 417 int 418 test_ipsec_status_check(struct rte_crypto_op *op, 419 const struct ipsec_test_flags *flags, 420 enum rte_security_ipsec_sa_direction dir, 421 int pkt_num) 422 { 423 int ret = TEST_SUCCESS; 424 425 if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && 426 flags->sa_expiry_pkts_hard && 427 pkt_num == IPSEC_TEST_PACKETS_MAX) { 428 if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) { 429 printf("SA hard expiry (pkts) test failed\n"); 430 return TEST_FAILED; 431 } else { 432 return TEST_SUCCESS; 433 } 434 } 435 436 if ((dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS) && 437 flags->tunnel_hdr_verify) { 438 if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) { 439 printf("Tunnel header verify test case failed\n"); 440 return TEST_FAILED; 441 } else { 442 return TEST_SUCCESS; 443 } 444 } 445 446 if (dir == RTE_SECURITY_IPSEC_SA_DIR_INGRESS && flags->icv_corrupt) { 447 if (op->status != RTE_CRYPTO_OP_STATUS_ERROR) { 448 printf("ICV corruption test case failed\n"); 449 ret = TEST_FAILED; 450 } 451 } else { 452 if (op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) { 453 printf("Security op processing failed [pkt_num: %d]\n", 454 pkt_num); 455 ret = TEST_FAILED; 456 } 457 } 458 459 if (flags->sa_expiry_pkts_soft && pkt_num == IPSEC_TEST_PACKETS_MAX) { 460 if (!(op->aux_flags & 461 RTE_CRYPTO_OP_AUX_FLAGS_IPSEC_SOFT_EXPIRY)) { 462 printf("SA soft expiry (pkts) test failed\n"); 463 ret = TEST_FAILED; 464 } 465 } 466 467 return ret; 468 } 469