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 39void 40utun_cleanup_crypto (struct utun_pcb *pcb) 41{ 42 utun_cleanup_all_crypto_ipsec(pcb); 43 // utun_cleanup_all_crypto_dtls(pcb); 44 pcb->utun_flags &= ~UTUN_FLAGS_CRYPTO; 45} 46 47errno_t 48utun_ctl_enable_crypto (__unused kern_ctl_ref kctlref, 49 __unused u_int32_t unit, 50 __unused void *unitinfo, 51 __unused int opt, 52 void *data, 53 size_t len) 54{ 55 struct utun_pcb *pcb = unitinfo; 56 57 /* 58 * - verify the crypto context args passed from user-land. 59 * - check the size of the argument buffer. 60 * - check the direction (IN or OUT) 61 * - check the type (IPSec or DTLS) 62 * - ensure that the crypto context is *not* already valid (don't recreate already valid context). 63 * - we have only one context per direction and type. 64 * - any error should be equivalent to noop. 65 */ 66 if (len < UTUN_CRYPTO_ARGS_HDR_SIZE) { 67 return EMSGSIZE; 68 } else { 69 int idx; 70 utun_crypto_args_t *crypto_args = (__typeof__(crypto_args))data; 71 utun_crypto_ctx_t *crypto_ctx; 72 73 if (crypto_args->ver == 0 || crypto_args->ver >= UTUN_CRYPTO_ARGS_VER_MAX) { 74 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_args->ver); 75 return EINVAL; 76 } 77 if (crypto_args->type == 0 || crypto_args->type >= UTUN_CRYPTO_TYPE_MAX) { 78 printf("%s: type check failed %d\n", __FUNCTION__, crypto_args->type); 79 return EINVAL; 80 } 81 if (len < UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)) { 82 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 83 (int)len, (int)UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)); 84 return EINVAL; 85 } 86 if (crypto_args->args_ulen != sizeof(crypto_args->u)) { 87 printf("%s: compatibility mode\n", __FUNCTION__); 88 } 89 if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 90 utun_ctl_enable_crypto_ipsec(pcb, crypto_args); 91 } else { 92 // unsupported 93 return EPROTONOSUPPORT; 94 } 95 for (idx = 0; idx < UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_MAX); idx++) { 96 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 97 if (crypto_ctx->valid) { 98 return EBADF; 99 } 100 101 crypto_ctx->type = crypto_args->type; 102 LIST_INIT(&crypto_ctx->keys_listhead); 103 crypto_ctx->valid = 1; 104 } 105 // data traffic is stopped by default 106 pcb->utun_flags |= (UTUN_FLAGS_CRYPTO | UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC); 107 return 0; 108 } 109} 110 111errno_t 112utun_ctl_disable_crypto (__unused kern_ctl_ref kctlref, 113 __unused u_int32_t unit, 114 __unused void *unitinfo, 115 __unused int opt, 116 void *data, 117 size_t len) 118{ 119 struct utun_pcb *pcb = unitinfo; 120 121 /* 122 * - verify the crypto context args passed from user-land. 123 * - check the size of the argument buffer. 124 * - check the direction (IN or OUT) 125 * - check the type (IPSec or DTLS) 126 * - ensure that the crypto context *is* already valid (don't release invalid context). 127 * - we have only one context per direction and type. 128 * - ensure that the crypto context has no crypto material. 129 * - any error should be equivalent to noop. 130 */ 131 if (len < UTUN_CRYPTO_ARGS_HDR_SIZE) { 132 return EMSGSIZE; 133 } else { 134 utun_crypto_args_t *crypto_args = (__typeof__(crypto_args))data; 135 136 if (crypto_args->ver == 0 || crypto_args->ver >= UTUN_CRYPTO_ARGS_VER_MAX) { 137 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_args->ver); 138 return EINVAL; 139 } 140 if (crypto_args->type == 0 || crypto_args->type >= UTUN_CRYPTO_TYPE_MAX) { 141 printf("%s: type check failed %d\n", __FUNCTION__, crypto_args->type); 142 return EINVAL; 143 } 144 if (len < UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)) { 145 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 146 (int)len, (int)UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)); 147 return EINVAL; 148 } 149 if (crypto_args->args_ulen != sizeof(crypto_args->u)) { 150 printf("%s: compatibility mode\n", __FUNCTION__); 151 } 152 153 if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 154 utun_ctl_disable_crypto_ipsec(pcb); 155 } else { 156 // unsupported 157 return EPROTONOSUPPORT; 158 } 159 } 160 pcb->utun_flags &= ~(UTUN_FLAGS_CRYPTO | UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC); 161 return 0; 162} 163 164errno_t 165utun_ctl_config_crypto_keys (__unused kern_ctl_ref kctlref, 166 __unused u_int32_t unit, 167 __unused void *unitinfo, 168 __unused int opt, 169 void *data, 170 size_t len) 171{ 172 struct utun_pcb *pcb = unitinfo; 173 174 /* 175 * - verify the crypto material args passed from user-land. 176 * - check the size of the argument buffer. 177 * - check the direction (IN or OUT) 178 * - check the type (IPSec or DTLS) 179 * - crypto material direction and type must match the associated crypto context's. 180 * - we can have a list of crypto materials per context. 181 * - ensure that the crypto context is already valid (don't add crypto material to invalid context). 182 * - any error should be equivalent to noop. 183 */ 184 if (len < UTUN_CRYPTO_KEYS_ARGS_HDR_SIZE) { 185 return EMSGSIZE; 186 } else { 187 int idx; 188 utun_crypto_keys_args_t *crypto_keys_args = (__typeof__(crypto_keys_args))data; 189 utun_crypto_ctx_t *crypto_ctx; 190 utun_crypto_keys_t *crypto_keys = NULL; 191 192 if (crypto_keys_args->ver == 0 || crypto_keys_args->ver >= UTUN_CRYPTO_KEYS_ARGS_VER_MAX) { 193 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_keys_args->ver); 194 return EINVAL; 195 } 196 if (crypto_keys_args->dir == 0 || crypto_keys_args->dir >= UTUN_CRYPTO_DIR_MAX) { 197 printf("%s: dir check failed %d\n", __FUNCTION__, crypto_keys_args->dir); 198 return EINVAL; 199 } 200 if (crypto_keys_args->type == 0 || crypto_keys_args->type >= UTUN_CRYPTO_TYPE_MAX) { 201 printf("%s: type check failed %d\n", __FUNCTION__, crypto_keys_args->type); 202 return EINVAL; 203 } 204 if (len < UTUN_CRYPTO_KEYS_ARGS_TOTAL_SIZE(crypto_keys_args)) { 205 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 206 (int)len, (int)UTUN_CRYPTO_KEYS_ARGS_TOTAL_SIZE(crypto_keys_args)); 207 return EINVAL; 208 } 209 idx = UTUN_CRYPTO_DIR_TO_IDX(crypto_keys_args->dir); 210 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 211 if (!crypto_ctx->valid) { 212 return EBADF; 213 } 214 if (crypto_keys_args->type != crypto_ctx->type) { 215 // can't add keymat to context with different crypto type 216 return ENOENT; 217 } 218 crypto_keys = utun_alloc(sizeof(*crypto_keys)); 219 if (!crypto_keys) { 220 return ENOBUFS; 221 } 222 bzero(crypto_keys, sizeof(*crypto_keys)); 223 if (crypto_keys_args->args_ulen != sizeof(crypto_keys_args->u)) { 224 printf("%s: compatibility mode\n", __FUNCTION__); 225 } 226 227 // branch-off for ipsec vs. dtls 228 if (crypto_keys_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 229 errno_t err; 230 if ((err = utun_ctl_config_crypto_keys_ipsec(pcb, crypto_keys_args, crypto_keys))) { 231 utun_free(crypto_keys); 232 return err; 233 } 234 } else { 235 // unsupported 236 utun_free(crypto_keys); 237 return EPROTONOSUPPORT; 238 } 239 crypto_keys->type = crypto_keys_args->type; 240 LIST_INSERT_HEAD(&crypto_ctx->keys_listhead, crypto_keys, chain); 241 crypto_keys->valid = 1; 242 } 243 244 return 0; 245} 246 247errno_t 248utun_ctl_unconfig_crypto_keys (__unused kern_ctl_ref kctlref, 249 __unused u_int32_t unit, 250 __unused void *unitinfo, 251 __unused int opt, 252 void *data, 253 size_t len) 254{ 255 struct utun_pcb *pcb = unitinfo; 256 257 /* 258 * - verify the crypto material args passed from user-land. 259 * - check the size of the argument buffer. 260 * - check the direction (IN or OUT) 261 * - check the type (IPSec or DTLS) 262 * - crypto material direction and type must match the associated crypto context's. 263 * - we can have a list of crypto materials per context. 264 * - ensure that the crypto context is already valid (don't add crypto material to invalid context). 265 * - any error should be equivalent to noop. 266 */ 267 if (len < UTUN_CRYPTO_KEYS_ARGS_HDR_SIZE) { 268 return EMSGSIZE; 269 } else { 270 int idx; 271 utun_crypto_keys_args_t *crypto_keys_args = (__typeof__(crypto_keys_args))data; 272 utun_crypto_ctx_t *crypto_ctx; 273 utun_crypto_keys_t *cur_crypto_keys, *nxt_crypto_keys; 274 275 if (crypto_keys_args->ver == 0 || crypto_keys_args->ver >= UTUN_CRYPTO_KEYS_ARGS_VER_MAX) { 276 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_keys_args->ver); 277 return EINVAL; 278 } 279 if (crypto_keys_args->dir == 0 || crypto_keys_args->dir >= UTUN_CRYPTO_DIR_MAX) { 280 printf("%s: dir check failed %d\n", __FUNCTION__, crypto_keys_args->dir); 281 return EINVAL; 282 } 283 if (crypto_keys_args->type == 0 || crypto_keys_args->type >= UTUN_CRYPTO_TYPE_MAX) { 284 printf("%s: type check failed %d\n", __FUNCTION__, crypto_keys_args->type); 285 return EINVAL; 286 } 287 if (len < UTUN_CRYPTO_KEYS_ARGS_TOTAL_SIZE(crypto_keys_args)) { 288 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 289 (int)len, (int)UTUN_CRYPTO_KEYS_ARGS_TOTAL_SIZE(crypto_keys_args)); 290 return EINVAL; 291 } 292 idx = UTUN_CRYPTO_DIR_TO_IDX(crypto_keys_args->dir); 293 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 294 if (!crypto_ctx->valid) { 295 return EBADF; 296 } 297 if (crypto_keys_args->type != crypto_ctx->type) { 298 // can't add keymat to context with different crypto type 299 return ENOENT; 300 } 301 if (crypto_keys_args->args_ulen != sizeof(crypto_keys_args->u)) { 302 printf("%s: compatibility mode\n", __FUNCTION__); 303 } 304 305 // traverse crypto materials looking for the right one 306 for (cur_crypto_keys = (__typeof__(cur_crypto_keys))LIST_FIRST(&crypto_ctx->keys_listhead); 307 cur_crypto_keys != NULL; 308 cur_crypto_keys = nxt_crypto_keys) { 309 nxt_crypto_keys = (__typeof__(nxt_crypto_keys))LIST_NEXT(cur_crypto_keys, chain); 310 // branch-off for ipsec vs. dtls 311 if (crypto_keys_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 312 if (crypto_keys_args->u.ipsec_v1.spi == cur_crypto_keys->state.u.ipsec.spi) { 313 errno_t err; 314 if ((err = utun_ctl_unconfig_crypto_keys_ipsec(crypto_keys_args, cur_crypto_keys))) { 315 return err; 316 } 317 LIST_REMOVE(cur_crypto_keys, chain); 318 bzero(cur_crypto_keys, sizeof(*cur_crypto_keys)); 319 utun_free(cur_crypto_keys); 320 return 0; 321 } 322 } else { 323 // unsupported 324 return EPROTONOSUPPORT; 325 } 326 } 327 // TODO: if there is no SA left, ensure utun can't decrypt/encrypt packets directly. it should rely on the vpnplugin for that. 328 } 329 330 return 0; 331} 332 333errno_t 334utun_ctl_generate_crypto_keys_idx (__unused kern_ctl_ref kctlref, 335 __unused u_int32_t unit, 336 __unused void *unitinfo, 337 __unused int opt, 338 void *data, 339 size_t *len) 340{ 341 struct utun_pcb *pcb = unitinfo; 342 343 /* 344 * - verify the crypto material index args passed from user-land. 345 * - check the size of the argument buffer. 346 * - check the direction (IN or OUT) 347 * - check the type (IPSec or DTLS) 348 * - crypto material direction and type must match the associated crypto context's. 349 * - we can have a list of crypto materials per context. 350 * - any error should be equivalent to noop. 351 */ 352 if (*len < UTUN_CRYPTO_KEYS_IDX_ARGS_HDR_SIZE) { 353 return EMSGSIZE; 354 } else { 355 int idx; 356 utun_crypto_keys_idx_args_t *crypto_keys_idx_args = (__typeof__(crypto_keys_idx_args))data; 357 utun_crypto_ctx_t *crypto_ctx; 358 359 if (crypto_keys_idx_args->ver == 0 || crypto_keys_idx_args->ver >= UTUN_CRYPTO_KEYS_ARGS_VER_MAX) { 360 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_keys_idx_args->ver); 361 return EINVAL; 362 } 363 if (crypto_keys_idx_args->dir == 0 || crypto_keys_idx_args->dir >= UTUN_CRYPTO_DIR_MAX) { 364 printf("%s: dir check failed %d\n", __FUNCTION__, crypto_keys_idx_args->dir); 365 return EINVAL; 366 } 367 if (crypto_keys_idx_args->type == 0 || crypto_keys_idx_args->type >= UTUN_CRYPTO_TYPE_MAX) { 368 printf("%s: type check failed %d\n", __FUNCTION__, crypto_keys_idx_args->type); 369 return EINVAL; 370 } 371 if (*len < UTUN_CRYPTO_KEYS_IDX_ARGS_TOTAL_SIZE(crypto_keys_idx_args)) { 372 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 373 (int)*len, (int)UTUN_CRYPTO_KEYS_IDX_ARGS_TOTAL_SIZE(crypto_keys_idx_args)); 374 return EINVAL; 375 } 376 idx = UTUN_CRYPTO_DIR_TO_IDX(crypto_keys_idx_args->dir); 377 crypto_ctx = &pcb->utun_crypto_ctx[idx]; 378 if (!crypto_ctx->valid) { 379 return EBADF; 380 } 381 if (crypto_keys_idx_args->type != crypto_ctx->type) { 382 // can't add keymat to context with different crypto type 383 return ENOENT; 384 } 385 if (crypto_keys_idx_args->args_ulen != sizeof(crypto_keys_idx_args->u)) { 386 printf("%s: compatibility mode\n", __FUNCTION__); 387 } 388 389 // traverse crypto materials looking for the right one 390 // branch-off for ipsec vs. dtls 391 if (crypto_keys_idx_args->type == UTUN_CRYPTO_TYPE_IPSEC) { 392 errno_t err; 393 if ((err = utun_ctl_generate_crypto_keys_idx_ipsec(crypto_keys_idx_args))) { 394 return err; 395 } 396 } else { 397 // unsupported 398 return EPROTONOSUPPORT; 399 } 400 } 401 402 return 0; 403} 404 405errno_t 406utun_ctl_stop_crypto_data_traffic (__unused kern_ctl_ref kctlref, 407 __unused u_int32_t unit, 408 __unused void *unitinfo, 409 __unused int opt, 410 void *data, 411 size_t len) 412{ 413 struct utun_pcb *pcb = unitinfo; 414 415 /* 416 * - verify the crypto context args passed from user-land. 417 * - check the size of the argument buffer. 418 * - check the direction (IN or OUT) 419 * - check the type (IPSec or DTLS) 420 * - ensure that the crypto context *is* already valid (don't release invalid context). 421 * - we have only one context per direction and type. 422 * - ensure that the crypto context has no crypto material. 423 * - any error should be equivalent to noop. 424 */ 425 if (len < UTUN_CRYPTO_ARGS_HDR_SIZE) { 426 return EMSGSIZE; 427 } else { 428 utun_crypto_args_t *crypto_args = (__typeof__(crypto_args))data; 429 430 if (crypto_args->ver == 0 || crypto_args->ver >= UTUN_CRYPTO_ARGS_VER_MAX) { 431 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_args->ver); 432 return EINVAL; 433 } 434 if (crypto_args->type == 0 || crypto_args->type >= UTUN_CRYPTO_TYPE_MAX) { 435 printf("%s: type check failed %d\n", __FUNCTION__, crypto_args->type); 436 return EINVAL; 437 } 438 if (len < UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)) { 439 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 440 (int)len, (int)UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)); 441 return EINVAL; 442 } 443 if (crypto_args->args_ulen != sizeof(crypto_args->u)) { 444 printf("%s: compatibility mode\n", __FUNCTION__); 445 } 446 447 if ((pcb->utun_flags & UTUN_FLAGS_CRYPTO) == 0) { 448 printf("%s: crypto is already disabled\n", __FUNCTION__); 449 return EINVAL; 450 } 451 452 if (crypto_args->type != UTUN_CRYPTO_TYPE_IPSEC) { 453 // unsupported 454 return EPROTONOSUPPORT; 455 } 456 } 457 pcb->utun_flags |= UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC; 458 return 0; 459} 460 461errno_t 462utun_ctl_start_crypto_data_traffic (__unused kern_ctl_ref kctlref, 463 __unused u_int32_t unit, 464 __unused void *unitinfo, 465 __unused int opt, 466 void *data, 467 size_t len) 468{ 469 struct utun_pcb *pcb = unitinfo; 470 471 /* 472 * - verify the crypto context args passed from user-land. 473 * - check the size of the argument buffer. 474 * - check the direction (IN or OUT) 475 * - check the type (IPSec or DTLS) 476 * - ensure that the crypto context *is* already valid (don't release invalid context). 477 * - we have only one context per direction and type. 478 * - ensure that the crypto context has no crypto material. 479 * - any error should be equivalent to noop. 480 */ 481 if (len < UTUN_CRYPTO_ARGS_HDR_SIZE) { 482 return EMSGSIZE; 483 } else { 484 utun_crypto_args_t *crypto_args = (__typeof__(crypto_args))data; 485 486 if (crypto_args->ver == 0 || crypto_args->ver >= UTUN_CRYPTO_ARGS_VER_MAX) { 487 printf("%s: ver check failed %d\n", __FUNCTION__, crypto_args->ver); 488 return EINVAL; 489 } 490 if (crypto_args->type == 0 || crypto_args->type >= UTUN_CRYPTO_TYPE_MAX) { 491 printf("%s: type check failed %d\n", __FUNCTION__, crypto_args->type); 492 return EINVAL; 493 } 494 if (len < UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)) { 495 printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__, 496 (int)len, (int)UTUN_CRYPTO_ARGS_TOTAL_SIZE(crypto_args)); 497 return EINVAL; 498 } 499 if (crypto_args->args_ulen != sizeof(crypto_args->u)) { 500 printf("%s: compatibility mode\n", __FUNCTION__); 501 } 502 503 if ((pcb->utun_flags & UTUN_FLAGS_CRYPTO) == 0) { 504 printf("%s: crypto is already disabled\n", __FUNCTION__); 505 return EINVAL; 506 } 507 508 if (crypto_args->type != UTUN_CRYPTO_TYPE_IPSEC) { 509 // unsupported 510 return EPROTONOSUPPORT; 511 } 512 } 513 pcb->utun_flags &= ~UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC; 514 return 0; 515} 516 517int 518utun_pkt_crypto_output (struct utun_pcb *pcb, mbuf_t *m) 519{ 520 int idx = UTUN_CRYPTO_DIR_TO_IDX(UTUN_CRYPTO_DIR_OUT); 521 if (!pcb->utun_crypto_ctx[idx].valid) { 522 printf("%s: context is invalid %d\n", __FUNCTION__, pcb->utun_crypto_ctx[idx].valid); 523 return -1; 524 } 525 if (pcb->utun_crypto_ctx[idx].type == UTUN_CRYPTO_TYPE_IPSEC) { 526 return(utun_pkt_ipsec_output(pcb, m)); 527 } else { 528 // unsupported 529 printf("%s: type is invalid %d\n", __FUNCTION__, pcb->utun_crypto_ctx[idx].type); 530 } 531 return -1; 532} 533