1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2016 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Security Associations 36 */ 37 #include <netinet/ip.h> 38 39 #include <rte_memzone.h> 40 #include <rte_crypto.h> 41 #include <rte_cryptodev.h> 42 #include <rte_byteorder.h> 43 #include <rte_errno.h> 44 45 #include "ipsec.h" 46 #include "esp.h" 47 48 /* SAs EP0 Outbound */ 49 const struct ipsec_sa sa_ep0_out[] = { 50 { 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5), 51 NULL, NULL, 52 esp4_tunnel_outbound_pre_crypto, 53 esp4_tunnel_outbound_post_crypto, 54 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 55 12, 16, 16, 56 0, 0 }, 57 { 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6), 58 NULL, NULL, 59 esp4_tunnel_outbound_pre_crypto, 60 esp4_tunnel_outbound_post_crypto, 61 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 62 12, 16, 16, 63 0, 0 }, 64 { 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7), 65 NULL, NULL, 66 esp4_tunnel_outbound_pre_crypto, 67 esp4_tunnel_outbound_post_crypto, 68 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 69 12, 16, 16, 70 0, 0 }, 71 { 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8), 72 NULL, NULL, 73 esp4_tunnel_outbound_pre_crypto, 74 esp4_tunnel_outbound_post_crypto, 75 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 76 12, 16, 16, 77 0, 0 }, 78 { 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5), 79 NULL, NULL, 80 esp4_tunnel_outbound_pre_crypto, 81 esp4_tunnel_outbound_post_crypto, 82 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL, 83 0, 0, 4, 84 0, 0 }, 85 }; 86 87 /* SAs EP0 Inbound */ 88 const struct ipsec_sa sa_ep0_in[] = { 89 { 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5), 90 NULL, NULL, 91 esp4_tunnel_inbound_pre_crypto, 92 esp4_tunnel_inbound_post_crypto, 93 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 94 12, 16, 16, 95 0, 0 }, 96 { 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6), 97 NULL, NULL, 98 esp4_tunnel_inbound_pre_crypto, 99 esp4_tunnel_inbound_post_crypto, 100 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 101 12, 16, 16, 102 0, 0 }, 103 { 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7), 104 NULL, NULL, 105 esp4_tunnel_inbound_pre_crypto, 106 esp4_tunnel_inbound_post_crypto, 107 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 108 12, 16, 16, 109 0, 0 }, 110 { 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8), 111 NULL, NULL, 112 esp4_tunnel_inbound_pre_crypto, 113 esp4_tunnel_inbound_post_crypto, 114 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 115 12, 16, 16, 116 0, 0 }, 117 { 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5), 118 NULL, NULL, 119 esp4_tunnel_inbound_pre_crypto, 120 esp4_tunnel_inbound_post_crypto, 121 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL, 122 0, 0, 4, 123 0, 0 }, 124 }; 125 126 /* SAs EP1 Outbound */ 127 const struct ipsec_sa sa_ep1_out[] = { 128 { 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5), 129 NULL, NULL, 130 esp4_tunnel_outbound_pre_crypto, 131 esp4_tunnel_outbound_post_crypto, 132 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 133 12, 16, 16, 134 0, 0 }, 135 { 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6), 136 NULL, NULL, 137 esp4_tunnel_outbound_pre_crypto, 138 esp4_tunnel_outbound_post_crypto, 139 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 140 12, 16, 16, 141 0, 0 }, 142 { 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7), 143 NULL, NULL, 144 esp4_tunnel_outbound_pre_crypto, 145 esp4_tunnel_outbound_post_crypto, 146 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 147 12, 16, 16, 148 0, 0 }, 149 { 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8), 150 NULL, NULL, 151 esp4_tunnel_outbound_pre_crypto, 152 esp4_tunnel_outbound_post_crypto, 153 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 154 12, 16, 16, 155 0, 0 }, 156 { 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5), 157 NULL, NULL, 158 esp4_tunnel_outbound_pre_crypto, 159 esp4_tunnel_outbound_post_crypto, 160 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL, 161 0, 0, 4, 162 0, 0 }, 163 }; 164 165 /* SAs EP1 Inbound */ 166 const struct ipsec_sa sa_ep1_in[] = { 167 { 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5), 168 NULL, NULL, 169 esp4_tunnel_inbound_pre_crypto, 170 esp4_tunnel_inbound_post_crypto, 171 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 172 12, 16, 16, 173 0, 0 }, 174 { 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6), 175 NULL, NULL, 176 esp4_tunnel_inbound_pre_crypto, 177 esp4_tunnel_inbound_post_crypto, 178 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 179 12, 16, 16, 180 0, 0 }, 181 { 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7), 182 NULL, NULL, 183 esp4_tunnel_inbound_pre_crypto, 184 esp4_tunnel_inbound_post_crypto, 185 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 186 12, 16, 16, 187 0, 0 }, 188 { 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8), 189 NULL, NULL, 190 esp4_tunnel_inbound_pre_crypto, 191 esp4_tunnel_inbound_post_crypto, 192 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC, 193 12, 16, 16, 194 0, 0 }, 195 { 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5), 196 NULL, NULL, 197 esp4_tunnel_inbound_pre_crypto, 198 esp4_tunnel_inbound_post_crypto, 199 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL, 200 0, 0, 4, 201 0, 0 }, 202 }; 203 204 static uint8_t cipher_key[256] = "sixteenbytes key"; 205 206 /* AES CBC xform */ 207 const struct rte_crypto_sym_xform aescbc_enc_xf = { 208 NULL, 209 RTE_CRYPTO_SYM_XFORM_CIPHER, 210 .cipher = { RTE_CRYPTO_CIPHER_OP_ENCRYPT, RTE_CRYPTO_CIPHER_AES_CBC, 211 .key = { cipher_key, 16 } } 212 }; 213 214 const struct rte_crypto_sym_xform aescbc_dec_xf = { 215 NULL, 216 RTE_CRYPTO_SYM_XFORM_CIPHER, 217 .cipher = { RTE_CRYPTO_CIPHER_OP_DECRYPT, RTE_CRYPTO_CIPHER_AES_CBC, 218 .key = { cipher_key, 16 } } 219 }; 220 221 static uint8_t auth_key[256] = "twentybytes hash key"; 222 223 /* SHA1 HMAC xform */ 224 const struct rte_crypto_sym_xform sha1hmac_gen_xf = { 225 NULL, 226 RTE_CRYPTO_SYM_XFORM_AUTH, 227 .auth = { RTE_CRYPTO_AUTH_OP_GENERATE, RTE_CRYPTO_AUTH_SHA1_HMAC, 228 .key = { auth_key, 20 }, 12, 0 } 229 }; 230 231 const struct rte_crypto_sym_xform sha1hmac_verify_xf = { 232 NULL, 233 RTE_CRYPTO_SYM_XFORM_AUTH, 234 .auth = { RTE_CRYPTO_AUTH_OP_VERIFY, RTE_CRYPTO_AUTH_SHA1_HMAC, 235 .key = { auth_key, 20 }, 12, 0 } 236 }; 237 238 /* AES CBC xform */ 239 const struct rte_crypto_sym_xform null_cipher_xf = { 240 NULL, 241 RTE_CRYPTO_SYM_XFORM_CIPHER, 242 .cipher = { .algo = RTE_CRYPTO_CIPHER_NULL } 243 }; 244 245 const struct rte_crypto_sym_xform null_auth_xf = { 246 NULL, 247 RTE_CRYPTO_SYM_XFORM_AUTH, 248 .auth = { .algo = RTE_CRYPTO_AUTH_NULL } 249 }; 250 251 struct sa_ctx { 252 struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES]; 253 struct { 254 struct rte_crypto_sym_xform a; 255 struct rte_crypto_sym_xform b; 256 } xf[IPSEC_SA_MAX_ENTRIES]; 257 }; 258 259 static struct sa_ctx * 260 sa_ipv4_create(const char *name, int socket_id) 261 { 262 char s[PATH_MAX]; 263 struct sa_ctx *sa_ctx; 264 unsigned mz_size; 265 const struct rte_memzone *mz; 266 267 snprintf(s, sizeof(s), "%s_%u", name, socket_id); 268 269 /* Create SA array table */ 270 printf("Creating SA context with %u maximum entries\n", 271 IPSEC_SA_MAX_ENTRIES); 272 273 mz_size = sizeof(struct sa_ctx); 274 mz = rte_memzone_reserve(s, mz_size, socket_id, 275 RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY); 276 if (mz == NULL) { 277 printf("Failed to allocate SA DB memory\n"); 278 rte_errno = -ENOMEM; 279 return NULL; 280 } 281 282 sa_ctx = (struct sa_ctx *)mz->addr; 283 284 return sa_ctx; 285 } 286 287 static int 288 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], 289 unsigned nb_entries, unsigned inbound) 290 { 291 struct ipsec_sa *sa; 292 unsigned i, idx; 293 294 for (i = 0; i < nb_entries; i++) { 295 idx = SPI2IDX(entries[i].spi); 296 sa = &sa_ctx->sa[idx]; 297 if (sa->spi != 0) { 298 printf("Index %u already in use by SPI %u\n", 299 idx, sa->spi); 300 return -EINVAL; 301 } 302 *sa = entries[i]; 303 sa->src = rte_cpu_to_be_32(sa->src); 304 sa->dst = rte_cpu_to_be_32(sa->dst); 305 if (inbound) { 306 if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) { 307 sa_ctx->xf[idx].a = null_auth_xf; 308 sa_ctx->xf[idx].b = null_cipher_xf; 309 } else { 310 sa_ctx->xf[idx].a = sha1hmac_verify_xf; 311 sa_ctx->xf[idx].b = aescbc_dec_xf; 312 } 313 } else { /* outbound */ 314 if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) { 315 sa_ctx->xf[idx].a = null_cipher_xf; 316 sa_ctx->xf[idx].b = null_auth_xf; 317 } else { 318 sa_ctx->xf[idx].a = aescbc_enc_xf; 319 sa_ctx->xf[idx].b = sha1hmac_gen_xf; 320 } 321 } 322 sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b; 323 sa_ctx->xf[idx].b.next = NULL; 324 sa->xforms = &sa_ctx->xf[idx].a; 325 } 326 327 return 0; 328 } 329 330 static inline int 331 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], 332 unsigned nb_entries) 333 { 334 return sa_add_rules(sa_ctx, entries, nb_entries, 0); 335 } 336 337 static inline int 338 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], 339 unsigned nb_entries) 340 { 341 return sa_add_rules(sa_ctx, entries, nb_entries, 1); 342 } 343 344 void 345 sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep) 346 { 347 const struct ipsec_sa *sa_out_entries, *sa_in_entries; 348 unsigned nb_out_entries, nb_in_entries; 349 const char *name; 350 351 if (ctx == NULL) 352 rte_exit(EXIT_FAILURE, "NULL context.\n"); 353 354 if (ctx->sa_ipv4_in != NULL) 355 rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already " 356 "initialized\n", socket_id); 357 358 if (ctx->sa_ipv4_out != NULL) 359 rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already " 360 "initialized\n", socket_id); 361 362 if (ep == 0) { 363 sa_out_entries = sa_ep0_out; 364 nb_out_entries = RTE_DIM(sa_ep0_out); 365 sa_in_entries = sa_ep0_in; 366 nb_in_entries = RTE_DIM(sa_ep0_in); 367 } else if (ep == 1) { 368 sa_out_entries = sa_ep1_out; 369 nb_out_entries = RTE_DIM(sa_ep1_out); 370 sa_in_entries = sa_ep1_in; 371 nb_in_entries = RTE_DIM(sa_ep1_in); 372 } else 373 rte_exit(EXIT_FAILURE, "Invalid EP value %u. " 374 "Only 0 or 1 supported.\n", ep); 375 376 name = "sa_ipv4_in"; 377 ctx->sa_ipv4_in = sa_ipv4_create(name, socket_id); 378 if (ctx->sa_ipv4_in == NULL) 379 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s " 380 "in socket %d\n", rte_errno, name, socket_id); 381 382 name = "sa_ipv4_out"; 383 ctx->sa_ipv4_out = sa_ipv4_create(name, socket_id); 384 if (ctx->sa_ipv4_out == NULL) 385 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s " 386 "in socket %d\n", rte_errno, name, socket_id); 387 388 sa_in_add_rules(ctx->sa_ipv4_in, sa_in_entries, nb_in_entries); 389 390 sa_out_add_rules(ctx->sa_ipv4_out, sa_out_entries, nb_out_entries); 391 } 392 393 int 394 inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx) 395 { 396 struct ipsec_mbuf_metadata *priv; 397 398 priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf)); 399 400 return (sa_ctx->sa[sa_idx].spi == priv->sa->spi); 401 } 402 403 void 404 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[], 405 struct ipsec_sa *sa[], uint16_t nb_pkts) 406 { 407 unsigned i; 408 uint32_t *src, spi; 409 410 for (i = 0; i < nb_pkts; i++) { 411 spi = rte_pktmbuf_mtod_offset(pkts[i], struct esp_hdr *, 412 sizeof(struct ip))->spi; 413 414 if (spi == INVALID_SPI) 415 continue; 416 417 sa[i] = &sa_ctx->sa[SPI2IDX(spi)]; 418 if (spi != sa[i]->spi) { 419 sa[i] = NULL; 420 continue; 421 } 422 423 src = rte_pktmbuf_mtod_offset(pkts[i], uint32_t *, 424 offsetof(struct ip, ip_src)); 425 if ((sa[i]->src != *src) || (sa[i]->dst != *(src + 1))) 426 sa[i] = NULL; 427 } 428 } 429 430 void 431 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[], 432 struct ipsec_sa *sa[], uint16_t nb_pkts) 433 { 434 unsigned i; 435 436 for (i = 0; i < nb_pkts; i++) 437 sa[i] = &sa_ctx->sa[sa_idx[i]]; 438 } 439