1/* 2 * Copyright (c) 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 30 31#include <sys/systm.h> 32#include <net/if.h> 33#include <net/if_types.h> 34#include <net/if_utun.h> 35#include <sys/mbuf.h> 36#include <net/if_utun_crypto.h> 37#include <net/if_utun_crypto_ipsec.h> 38#include <net/if_utun_crypto_dtls.h> 39 40void 41utun_ctl_init_crypto (void) 42{ 43 utun_ctl_init_crypto_dtls(); 44} 45 46void 47utun_cleanup_crypto (struct utun_pcb *pcb) 48{ 49#if IPSEC 50 utun_cleanup_all_crypto_ipsec(pcb); 51#endif 52 utun_cleanup_all_crypto_dtls(pcb); 53 pcb->utun_flags &= ~UTUN_FLAGS_CRYPTO; 54} 55 56errno_t 57utun_ctl_enable_crypto (__unused kern_ctl_ref kctlref, 58 __unused u_int32_t unit, 59 __unused void *unitinfo, 60 __unused int opt, 61 void *data, 62 size_t len) 63{ 64 struct utun_pcb *pcb = unitinfo; 65 66 /* 67 * - verify the crypto context args passed from user-land. 68 * - check the size of the argument buffer. 69 * - check the direction (IN or OUT) 70 * - check the type (IPSec or DTLS) 71 * - ensure that the crypto context is *not* already valid (don't recreate already valid context). 72 * - we have only one context per direction and type. 73 * - any error should be equivalent to noop. 74 */ 75 if (len < UTUN_CRYPTO_ARGS_HDR_SIZE) { 76 return EMSGSIZE; 77 } else { 78 int idx; 79 utun_crypto_args_t *crypto_args = (__typeof__(crypto_args))data; 80 utun_crypto_ctx_t *crypto_ctx; 81 82 if (crypto_args->ver == 0 || crypto_args->ver >= UTUN_CRYPTO_ARGS_VER_MAX) { 83 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_args->ver); 84 return EINVAL; 85 } 86 if (crypto_args->type == 0 || crypto_args->type >= UTUN_CRYPTO_TYPE_MAX) { 87 printf("%s: type check failed %d\n", __FUNCTION__, crypto_args->type); 88 return EINVAL; 89 } 90 if (len < UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)) { 91 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 92 (int)len, (int)UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)); 93 return EINVAL; 94 } 95 if (crypto_args->args_ulen != sizeof(crypto_args->u)) { 96 printf("%s: compatibility mode\n", __FUNCTION__); 97 } 98 99#if IPSEC 100 if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 101 utun_ctl_enable_crypto_ipsec(pcb, crypto_args); 102 } else 103#endif 104 if (crypto_args->type == UTUN_CRYPTO_TYPE_DTLS) { 105 utun_ctl_enable_crypto_dtls(pcb, crypto_args); 106 } else { 107 // unsupported 108 return EPROTONOSUPPORT; 109 } 110 for (idx = 0; idx < UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_MAX); idx++) { 111 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 112 if (crypto_ctx->valid) { 113 return EBADF; 114 } 115 116 crypto_ctx->type = crypto_args->type; 117 LIST_INIT(&crypto_ctx->keys_listhead); 118 LIST_INIT(&crypto_ctx->framer_listheads[UTUN_CRYPTO_INNER_TYPE_TO_IDX(UTUN_CRYPTO_INNER_TYPE_IPv4)]); 119 LIST_INIT(&crypto_ctx->framer_listheads[UTUN_CRYPTO_INNER_TYPE_TO_IDX(UTUN_CRYPTO_INNER_TYPE_IPv6)]); 120 crypto_ctx->valid = 1; 121 printf("%s: initialized framer lists\n", __FUNCTION__); 122 } 123 // data traffic is stopped by default 124 pcb->utun_flags |= (UTUN_FLAGS_CRYPTO | UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC); 125 return 0; 126 } 127} 128 129errno_t 130utun_ctl_disable_crypto (__unused kern_ctl_ref kctlref, 131 __unused u_int32_t unit, 132 __unused void *unitinfo, 133 __unused int opt, 134 void *data, 135 size_t len) 136{ 137 struct utun_pcb *pcb = unitinfo; 138 139 /* 140 * - verify the crypto context args passed from user-land. 141 * - check the size of the argument buffer. 142 * - check the direction (IN or OUT) 143 * - check the type (IPSec or DTLS) 144 * - ensure that the crypto context *is* already valid (don't release invalid context). 145 * - we have only one context per direction and type. 146 * - ensure that the crypto context has no crypto material. 147 * - any error should be equivalent to noop. 148 */ 149 if (len < UTUN_CRYPTO_ARGS_HDR_SIZE) { 150 return EMSGSIZE; 151 } else { 152 utun_crypto_args_t *crypto_args = (__typeof__(crypto_args))data; 153 154 if (crypto_args->ver == 0 || crypto_args->ver >= UTUN_CRYPTO_ARGS_VER_MAX) { 155 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_args->ver); 156 return EINVAL; 157 } 158 if (crypto_args->type == 0 || crypto_args->type >= UTUN_CRYPTO_TYPE_MAX) { 159 printf("%s: type check failed %d\n", __FUNCTION__, crypto_args->type); 160 return EINVAL; 161 } 162 if (len < UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)) { 163 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 164 (int)len, (int)UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)); 165 return EINVAL; 166 } 167 if (crypto_args->args_ulen != sizeof(crypto_args->u)) { 168 printf("%s: compatibility mode\n", __FUNCTION__); 169 } 170 171#if IPSEC 172 if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 173 utun_ctl_disable_crypto_ipsec(pcb); 174 } else 175#endif 176 if (crypto_args->type == UTUN_CRYPTO_TYPE_DTLS) { 177 utun_ctl_disable_crypto_dtls(pcb); 178 } else { 179 // unsupported 180 return EPROTONOSUPPORT; 181 } 182 } 183 pcb->utun_flags &= ~(UTUN_FLAGS_CRYPTO | UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC); 184 return 0; 185} 186 187errno_t 188utun_ctl_config_crypto_keys (__unused kern_ctl_ref kctlref, 189 __unused u_int32_t unit, 190 __unused void *unitinfo, 191 __unused int opt, 192 void *data, 193 size_t len) 194{ 195 struct utun_pcb *pcb = unitinfo; 196 197 /* 198 * - verify the crypto material args passed from user-land. 199 * - check the size of the argument buffer. 200 * - check the direction (IN or OUT) 201 * - check the type (IPSec only) 202 * - crypto material direction and type must match the associated crypto context's. 203 * - we can have a list of crypto materials per context. 204 * - ensure that the crypto context is already valid (don't add crypto material to invalid context). 205 * - any error should be equivalent to noop. 206 */ 207 if (len < UTUN_CRYPTO_KEYS_ARGS_HDR_SIZE) { 208 return EMSGSIZE; 209 } else { 210 int idx; 211 utun_crypto_keys_args_t *crypto_keys_args = (__typeof__(crypto_keys_args))data; 212 utun_crypto_ctx_t *crypto_ctx; 213 utun_crypto_keys_t *crypto_keys = NULL; 214 215 if (crypto_keys_args->ver == 0 || crypto_keys_args->ver >= UTUN_CRYPTO_KEYS_ARGS_VER_MAX) { 216 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_keys_args->ver); 217 return EINVAL; 218 } 219 if (crypto_keys_args->dir == 0 || crypto_keys_args->dir >= UTUN_CRYPTO_DIR_MAX) { 220 printf("%s: dir check failed %d\n", __FUNCTION__, crypto_keys_args->dir); 221 return EINVAL; 222 } 223 if (crypto_keys_args->type == 0 || crypto_keys_args->type >= UTUN_CRYPTO_TYPE_MAX) { 224 printf("%s: type check failed %d\n", __FUNCTION__, crypto_keys_args->type); 225 return EINVAL; 226 } 227 if (len < UTUN_CRYPTO_KEYS_ARGS_TOTAL_SIZE(crypto_keys_args)) { 228 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 229 (int)len, (int)UTUN_CRYPTO_KEYS_ARGS_TOTAL_SIZE(crypto_keys_args)); 230 return EINVAL; 231 } 232 idx = UTUN_CRYPTO_DIR_TO_IDX(crypto_keys_args->dir); 233 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 234 if (!crypto_ctx->valid) { 235 return EBADF; 236 } 237 if (crypto_keys_args->type != crypto_ctx->type) { 238 // can't add keymat to context with different crypto type 239 return ENOENT; 240 } 241 crypto_keys = utun_alloc(sizeof(*crypto_keys)); 242 if (!crypto_keys) { 243 return ENOBUFS; 244 } 245 bzero(crypto_keys, sizeof(*crypto_keys)); 246 if (crypto_keys_args->args_ulen != sizeof(crypto_keys_args->u)) { 247 printf("%s: compatibility mode\n", __FUNCTION__); 248 } 249 250 // branch-off for ipsec vs. dtls 251#if IPSEC 252 if (crypto_keys_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 253 errno_t err; 254 if ((err = utun_ctl_config_crypto_keys_ipsec(pcb, crypto_keys_args, crypto_keys))) { 255 utun_free(crypto_keys); 256 return err; 257 } 258 } else 259#endif 260 { 261 // unsupported 262 utun_free(crypto_keys); 263 return EPROTONOSUPPORT; 264 } 265 crypto_keys->type = crypto_keys_args->type; 266 LIST_INSERT_HEAD(&crypto_ctx->keys_listhead, crypto_keys, chain); 267 crypto_keys->valid = 1; 268 } 269 270 return 0; 271} 272 273errno_t 274utun_ctl_unconfig_crypto_keys (__unused kern_ctl_ref kctlref, 275 __unused u_int32_t unit, 276 __unused void *unitinfo, 277 __unused int opt, 278 void *data, 279 size_t len) 280{ 281 struct utun_pcb *pcb = unitinfo; 282 283 /* 284 * - verify the crypto material args passed from user-land. 285 * - check the size of the argument buffer. 286 * - check the direction (IN or OUT) 287 * - check the type (IPSec only) 288 * - crypto material direction and type must match the associated crypto context's. 289 * - we can have a list of crypto materials per context. 290 * - ensure that the crypto context is already valid (don't add crypto material to invalid context). 291 * - any error should be equivalent to noop. 292 */ 293 if (len < UTUN_CRYPTO_KEYS_ARGS_HDR_SIZE) { 294 return EMSGSIZE; 295 } else { 296 int idx; 297 utun_crypto_keys_args_t *crypto_keys_args = (__typeof__(crypto_keys_args))data; 298 utun_crypto_ctx_t *crypto_ctx; 299 utun_crypto_keys_t *cur_crypto_keys, *nxt_crypto_keys; 300 301 if (crypto_keys_args->ver == 0 || crypto_keys_args->ver >= UTUN_CRYPTO_KEYS_ARGS_VER_MAX) { 302 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_keys_args->ver); 303 return EINVAL; 304 } 305 if (crypto_keys_args->dir == 0 || crypto_keys_args->dir >= UTUN_CRYPTO_DIR_MAX) { 306 printf("%s: dir check failed %d\n", __FUNCTION__, crypto_keys_args->dir); 307 return EINVAL; 308 } 309 if (crypto_keys_args->type == 0 || crypto_keys_args->type >= UTUN_CRYPTO_TYPE_MAX) { 310 printf("%s: type check failed %d\n", __FUNCTION__, crypto_keys_args->type); 311 return EINVAL; 312 } 313 if (len < UTUN_CRYPTO_KEYS_ARGS_TOTAL_SIZE(crypto_keys_args)) { 314 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 315 (int)len, (int)UTUN_CRYPTO_KEYS_ARGS_TOTAL_SIZE(crypto_keys_args)); 316 return EINVAL; 317 } 318 idx = UTUN_CRYPTO_DIR_TO_IDX(crypto_keys_args->dir); 319 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 320 if (!crypto_ctx->valid) { 321 return EBADF; 322 } 323 if (crypto_keys_args->type != crypto_ctx->type) { 324 // can't add keymat to context with different crypto type 325 return ENOENT; 326 } 327 if (crypto_keys_args->args_ulen != sizeof(crypto_keys_args->u)) { 328 printf("%s: compatibility mode\n", __FUNCTION__); 329 } 330 331 // traverse crypto materials looking for the right one 332 for (cur_crypto_keys = (__typeof__(cur_crypto_keys))LIST_FIRST(&crypto_ctx->keys_listhead); 333 cur_crypto_keys != NULL; 334 cur_crypto_keys = nxt_crypto_keys) { 335 nxt_crypto_keys = (__typeof__(nxt_crypto_keys))LIST_NEXT(cur_crypto_keys, chain); 336 // branch-off for ipsec vs. dtls 337#if IPSEC 338 if (crypto_keys_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 339 if (crypto_keys_args->u.ipsec_v1.spi == cur_crypto_keys->state.u.ipsec.spi) { 340 errno_t err; 341 if ((err = utun_ctl_unconfig_crypto_keys_ipsec(crypto_keys_args, cur_crypto_keys))) { 342 return err; 343 } 344 LIST_REMOVE(cur_crypto_keys, chain); 345 bzero(cur_crypto_keys, sizeof(*cur_crypto_keys)); 346 utun_free(cur_crypto_keys); 347 return 0; 348 } 349 } else 350#endif 351 { 352 // unsupported 353 return EPROTONOSUPPORT; 354 } 355 } 356 // TODO: if there is no SA left, ensure utun can't decrypt/encrypt packets directly. it should rely on the vpnplugin for that. 357 } 358 359 return 0; 360} 361 362errno_t 363utun_ctl_config_crypto_framer (__unused kern_ctl_ref kctlref, 364 __unused u_int32_t unit, 365 __unused void *unitinfo, 366 __unused int opt, 367 void *data, 368 size_t len) 369{ 370 struct utun_pcb *pcb = unitinfo; 371 372 /* 373 * - verify the crypto material args passed from user-land. 374 * - check the size of the argument buffer. 375 * - check the direction (IN or OUT) 376 * - check the type (DTLS only) 377 * - crypto material direction and type must match the associated crypto context's. 378 * - we can have a list of crypto materials per context. 379 * - ensure that the crypto context is already valid (don't add crypto material to invalid context). 380 * - any error should be equivalent to noop. 381 */ 382 if (len < UTUN_CRYPTO_FRAMER_ARGS_HDR_SIZE) { 383 return EMSGSIZE; 384 } else { 385 int idx; 386 utun_crypto_framer_args_t *framer_args = (__typeof__(framer_args))data; 387 utun_crypto_ctx_t *crypto_ctx; 388 389 if (framer_args->ver == 0 || framer_args->ver >= UTUN_CRYPTO_FRAMER_ARGS_VER_MAX) { 390 printf("%s: ver check failed %d\n", __FUNCTION__, (int)framer_args->ver); 391 return EINVAL; 392 } 393 if (framer_args->dir == 0 || framer_args->dir >= UTUN_CRYPTO_DIR_MAX) { 394 printf("%s: dir check failed %d\n", __FUNCTION__, (int)framer_args->dir); 395 return EINVAL; 396 } 397 if (framer_args->type == 0 || framer_args->type >= UTUN_CRYPTO_TYPE_MAX) { 398 printf("%s: type check failed %d\n", __FUNCTION__, (int)framer_args->type); 399 return EINVAL; 400 } 401 if (len < UTUN_CRYPTO_FRAMER_ARGS_TOTAL_SIZE(framer_args)) { 402 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 403 (int)len, (int)UTUN_CRYPTO_FRAMER_ARGS_TOTAL_SIZE(framer_args)); 404 return EINVAL; 405 } 406 idx = UTUN_CRYPTO_DIR_TO_IDX(framer_args->dir); 407 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 408 if (!crypto_ctx->valid) { 409 return EBADF; 410 } 411 if (framer_args->type != crypto_ctx->type) { 412 // can't add keymat to context with different crypto type 413 return ENOENT; 414 } 415 if (framer_args->args_ulen != sizeof(framer_args->u)) { 416 printf("%s: compatibility mode\n", __FUNCTION__); 417 // TODO: 418 } 419 420 // branch-off for ipsec vs. dtls 421 if (framer_args->type == UTUN_CRYPTO_TYPE_DTLS) { 422 errno_t err; 423 if ((err = utun_ctl_config_crypto_dtls_framer(crypto_ctx, framer_args))) { 424 return err; 425 } 426 } else { 427 // unsupported 428 return EPROTONOSUPPORT; 429 } 430 } 431 432 return 0; 433} 434 435errno_t 436utun_ctl_unconfig_crypto_framer (__unused kern_ctl_ref kctlref, 437 __unused u_int32_t unit, 438 __unused void *unitinfo, 439 __unused int opt, 440 void *data, 441 size_t len) 442{ 443 struct utun_pcb *pcb = unitinfo; 444 445 /* 446 * - verify the crypto material args passed from user-land. 447 * - check the size of the argument buffer. 448 * - check the direction (IN or OUT) 449 * - check the type (DTLS only) 450 * - crypto material direction and type must match the associated crypto context's. 451 * - we can have a list of crypto materials per context. 452 * - ensure that the crypto context is already valid (don't add crypto material to invalid context). 453 * - any error should be equivalent to noop. 454 */ 455 if (len < UTUN_CRYPTO_FRAMER_ARGS_HDR_SIZE) { 456 return EMSGSIZE; 457 } else { 458 int idx; 459 utun_crypto_framer_args_t *framer_args = (__typeof__(framer_args))data; 460 utun_crypto_ctx_t *crypto_ctx; 461 462 if (framer_args->ver == 0 || framer_args->ver >= UTUN_CRYPTO_FRAMER_ARGS_VER_MAX) { 463 printf("%s: ver check failed %d\n", __FUNCTION__, (int)framer_args->ver); 464 return EINVAL; 465 } 466 if (framer_args->dir == 0 || framer_args->dir >= UTUN_CRYPTO_DIR_MAX) { 467 printf("%s: dir check failed %d\n", __FUNCTION__, (int)framer_args->dir); 468 return EINVAL; 469 } 470 if (framer_args->type == 0 || framer_args->type >= UTUN_CRYPTO_TYPE_MAX) { 471 printf("%s: type check failed %d\n", __FUNCTION__, (int)framer_args->type); 472 return EINVAL; 473 } 474 if (len < UTUN_CRYPTO_FRAMER_ARGS_TOTAL_SIZE(framer_args)) { 475 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 476 (int)len, (int)UTUN_CRYPTO_FRAMER_ARGS_TOTAL_SIZE(framer_args)); 477 return EINVAL; 478 } 479 idx = UTUN_CRYPTO_DIR_TO_IDX(framer_args->dir); 480 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 481 if (!crypto_ctx->valid) { 482 return EBADF; 483 } 484 if (framer_args->type != crypto_ctx->type) { 485 // can't add keymat to context with different crypto type 486 return ENOENT; 487 } 488 if (framer_args->args_ulen != sizeof(framer_args->u)) { 489 printf("%s: compatibility mode\n", __FUNCTION__); 490 } 491 492 // branch-off for ipsec vs. dtls 493 if (framer_args->type == UTUN_CRYPTO_TYPE_DTLS) { 494 errno_t err; 495 if ((err = utun_ctl_unconfig_crypto_dtls_framer(crypto_ctx, framer_args))) { 496 return err; 497 } 498 } else { 499 // unsupported 500 return EPROTONOSUPPORT; 501 } 502 } 503 504 return 0; 505} 506 507errno_t 508utun_ctl_generate_crypto_keys_idx (__unused kern_ctl_ref kctlref, 509 __unused u_int32_t unit, 510 __unused void *unitinfo, 511 __unused int opt, 512 void *data, 513 size_t *len) 514{ 515 struct utun_pcb *pcb = unitinfo; 516 517 /* 518 * - verify the crypto material index args passed from user-land. 519 * - check the size of the argument buffer. 520 * - check the direction (IN or OUT) 521 * - check the type (IPSec only) 522 * - crypto material direction and type must match the associated crypto context's. 523 * - we can have a list of crypto materials per context. 524 * - any error should be equivalent to noop. 525 */ 526 if (*len < UTUN_CRYPTO_KEYS_IDX_ARGS_HDR_SIZE) { 527 return EMSGSIZE; 528 } else { 529 int idx; 530 utun_crypto_keys_idx_args_t *crypto_keys_idx_args = (__typeof__(crypto_keys_idx_args))data; 531 utun_crypto_ctx_t *crypto_ctx; 532 533 if (crypto_keys_idx_args->ver == 0 || crypto_keys_idx_args->ver >= UTUN_CRYPTO_KEYS_ARGS_VER_MAX) { 534 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_keys_idx_args->ver); 535 return EINVAL; 536 } 537 if (crypto_keys_idx_args->dir == 0 || crypto_keys_idx_args->dir >= UTUN_CRYPTO_DIR_MAX) { 538 printf("%s: dir check failed %d\n", __FUNCTION__, crypto_keys_idx_args->dir); 539 return EINVAL; 540 } 541 if (crypto_keys_idx_args->type == 0 || crypto_keys_idx_args->type >= UTUN_CRYPTO_TYPE_MAX) { 542 printf("%s: type check failed %d\n", __FUNCTION__, crypto_keys_idx_args->type); 543 return EINVAL; 544 } 545 if (*len < UTUN_CRYPTO_KEYS_IDX_ARGS_TOTAL_SIZE(crypto_keys_idx_args)) { 546 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 547 (int)*len, (int)UTUN_CRYPTO_KEYS_IDX_ARGS_TOTAL_SIZE(crypto_keys_idx_args)); 548 return EINVAL; 549 } 550 idx = UTUN_CRYPTO_DIR_TO_IDX(crypto_keys_idx_args->dir); 551 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 552 if (!crypto_ctx->valid) { 553 return EBADF; 554 } 555 if (crypto_keys_idx_args->type != crypto_ctx->type) { 556 // can't add keymat to context with different crypto type 557 return ENOENT; 558 } 559 if (crypto_keys_idx_args->args_ulen != sizeof(crypto_keys_idx_args->u)) { 560 printf("%s: compatibility mode\n", __FUNCTION__); 561 } 562 563 // traverse crypto materials looking for the right one 564 // branch-off for ipsec vs. dtls 565#if IPSEC 566 if (crypto_keys_idx_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 567 errno_t err; 568 if ((err = utun_ctl_generate_crypto_keys_idx_ipsec(crypto_keys_idx_args))) { 569 return err; 570 } 571 } else 572#endif 573 { 574 // unsupported 575 return EPROTONOSUPPORT; 576 } 577 } 578 579 return 0; 580} 581 582errno_t 583utun_ctl_stop_crypto_data_traffic (__unused kern_ctl_ref kctlref, 584 __unused u_int32_t unit, 585 __unused void *unitinfo, 586 __unused int opt, 587 void *data, 588 size_t len) 589{ 590 struct utun_pcb *pcb = unitinfo; 591 592 /* 593 * - verify the crypto context args passed from user-land. 594 * - check the size of the argument buffer. 595 * - check the direction (IN or OUT) 596 * - check the type (IPSec or DTLS) 597 * - ensure that the crypto context *is* already valid (don't release invalid context). 598 * - we have only one context per direction and type. 599 * - ensure that the crypto context has no crypto material. 600 * - any error should be equivalent to noop. 601 */ 602 if (len < UTUN_CRYPTO_ARGS_HDR_SIZE) { 603 return EMSGSIZE; 604 } else { 605 utun_crypto_args_t *crypto_args = (__typeof__(crypto_args))data; 606 607 if (crypto_args->ver == 0 || crypto_args->ver >= UTUN_CRYPTO_ARGS_VER_MAX) { 608 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_args->ver); 609 return EINVAL; 610 } 611 if (crypto_args->type == 0 || crypto_args->type >= UTUN_CRYPTO_TYPE_MAX) { 612 printf("%s: type check failed %d\n", __FUNCTION__, crypto_args->type); 613 return EINVAL; 614 } 615 if (len < UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)) { 616 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 617 (int)len, (int)UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)); 618 return EINVAL; 619 } 620 if (crypto_args->args_ulen != sizeof(crypto_args->u)) { 621 printf("%s: compatibility mode\n", __FUNCTION__); 622 } 623 624 if ((pcb->utun_flags & UTUN_FLAGS_CRYPTO) == 0) { 625 printf("%s: crypto is already disabled\n", __FUNCTION__); 626 return EINVAL; 627 } 628 629 if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 630 // nothing 631 } else if (crypto_args->type == UTUN_CRYPTO_TYPE_DTLS) { 632 utun_ctl_stop_datatraffic_crypto_dtls(pcb); 633 } else { 634 // unsupported 635 return EPROTONOSUPPORT; 636 } 637 } 638 pcb->utun_flags |= UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC; 639 return 0; 640} 641 642errno_t 643utun_ctl_start_crypto_data_traffic (__unused kern_ctl_ref kctlref, 644 __unused u_int32_t unit, 645 __unused void *unitinfo, 646 __unused int opt, 647 void *data, 648 size_t len) 649{ 650 struct utun_pcb *pcb = unitinfo; 651 652 /* 653 * - verify the crypto context args passed from user-land. 654 * - check the size of the argument buffer. 655 * - check the direction (IN or OUT) 656 * - check the type (IPSec or DTLS) 657 * - ensure that the crypto context *is* already valid (don't release invalid context). 658 * - we have only one context per direction and type. 659 * - ensure that the crypto context has no crypto material. 660 * - any error should be equivalent to noop. 661 */ 662 if (len < UTUN_CRYPTO_ARGS_HDR_SIZE) { 663 return EMSGSIZE; 664 } else { 665 utun_crypto_args_t *crypto_args = (__typeof__(crypto_args))data; 666 667 if (crypto_args->ver == 0 || crypto_args->ver >= UTUN_CRYPTO_ARGS_VER_MAX) { 668 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_args->ver); 669 return EINVAL; 670 } 671 if (crypto_args->type == 0 || crypto_args->type >= UTUN_CRYPTO_TYPE_MAX) { 672 printf("%s: type check failed %d\n", __FUNCTION__, crypto_args->type); 673 return EINVAL; 674 } 675 if (len < UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)) { 676 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 677 (int)len, (int)UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)); 678 return EINVAL; 679 } 680 if (crypto_args->args_ulen != sizeof(crypto_args->u)) { 681 printf("%s: compatibility mode\n", __FUNCTION__); 682 } 683 684 if ((pcb->utun_flags & UTUN_FLAGS_CRYPTO) == 0) { 685 printf("%s: crypto is already disabled\n", __FUNCTION__); 686 return EINVAL; 687 } 688 689 if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 690 // nothing 691 } else if (crypto_args->type == UTUN_CRYPTO_TYPE_DTLS) { 692 utun_ctl_start_datatraffic_crypto_dtls(pcb); 693 } else { 694 // unsupported 695 return EPROTONOSUPPORT; 696 } 697 } 698 pcb->utun_flags &= ~UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC; 699 return 0; 700} 701 702int 703utun_pkt_crypto_output (struct utun_pcb *pcb, mbuf_t *m) 704{ 705 int idx = UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_OUT); 706 if (!pcb->utun_crypto_ctx[idx].valid) { 707 printf("%s: context is invalid %d\n", __FUNCTION__, pcb->utun_crypto_ctx[idx].valid); 708 return -1; 709 } 710#if IPSEC 711 if (pcb->utun_crypto_ctx[idx].type == UTUN_CRYPTO_TYPE_IPSEC) { 712 return(utun_pkt_ipsec_output(pcb, m)); 713 } else 714#endif 715 if (pcb->utun_crypto_ctx[idx].type == UTUN_CRYPTO_TYPE_DTLS) { 716 return(utun_pkt_dtls_output(pcb, m)); 717 } else { 718 // unsupported 719 printf("%s: type is invalid %d\n", __FUNCTION__, pcb->utun_crypto_ctx[idx].type); 720 } 721 return -1; 722} 723