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