]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/if_utun_crypto.c
xnu-2782.20.48.tar.gz
[apple/xnu.git] / bsd / net / if_utun_crypto.c
index 176f4cd663bbc667b25bc5f44b14de948d5ff983..553d4874c0324880e2a5c90d123fe471d4591d62 100644 (file)
 #include <sys/mbuf.h> 
 #include <net/if_utun_crypto.h>
 #include <net/if_utun_crypto_ipsec.h>
+#include <net/if_utun_crypto_dtls.h>
+
+void
+utun_ctl_init_crypto (void)
+{
+       utun_ctl_init_crypto_dtls();
+}
 
 void
 utun_cleanup_crypto (struct utun_pcb *pcb)
 {
+#if IPSEC
        utun_cleanup_all_crypto_ipsec(pcb);
-       // utun_cleanup_all_crypto_dtls(pcb);
+#endif
+       utun_cleanup_all_crypto_dtls(pcb);
        pcb->utun_flags &= ~UTUN_FLAGS_CRYPTO;
 }
 
@@ -86,8 +95,14 @@ utun_ctl_enable_crypto (__unused kern_ctl_ref  kctlref,
                if (crypto_args->args_ulen != sizeof(crypto_args->u)) {
                        printf("%s: compatibility mode\n", __FUNCTION__);
                }
+
+#if IPSEC
                if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) {
                        utun_ctl_enable_crypto_ipsec(pcb, crypto_args);
+               } else
+#endif
+               if (crypto_args->type == UTUN_CRYPTO_TYPE_DTLS) {
+                       utun_ctl_enable_crypto_dtls(pcb, crypto_args);
                } else {
                        // unsupported
                        return EPROTONOSUPPORT;
@@ -100,7 +115,10 @@ utun_ctl_enable_crypto (__unused kern_ctl_ref  kctlref,
 
                        crypto_ctx->type = crypto_args->type;
                        LIST_INIT(&crypto_ctx->keys_listhead);
+                       LIST_INIT(&crypto_ctx->framer_listheads[UTUN_CRYPTO_INNER_TYPE_TO_IDX(UTUN_CRYPTO_INNER_TYPE_IPv4)]);
+                       LIST_INIT(&crypto_ctx->framer_listheads[UTUN_CRYPTO_INNER_TYPE_TO_IDX(UTUN_CRYPTO_INNER_TYPE_IPv6)]);
                        crypto_ctx->valid = 1;
+                       printf("%s: initialized framer lists\n", __FUNCTION__);
                }
                // data traffic is stopped by default
                pcb->utun_flags |= (UTUN_FLAGS_CRYPTO | UTUN_FLAGS_CRYPTO_STOP_DATA_TRAFFIC);
@@ -150,8 +168,13 @@ utun_ctl_disable_crypto (__unused kern_ctl_ref  kctlref,
                        printf("%s: compatibility mode\n", __FUNCTION__);
                }
 
+#if IPSEC
                if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) {
                        utun_ctl_disable_crypto_ipsec(pcb);
+               } else 
+#endif
+               if (crypto_args->type == UTUN_CRYPTO_TYPE_DTLS) {
+                       utun_ctl_disable_crypto_dtls(pcb);
                } else {
                        // unsupported
                        return EPROTONOSUPPORT;
@@ -175,7 +198,7 @@ utun_ctl_config_crypto_keys (__unused kern_ctl_ref  kctlref,
         * - verify the crypto material args passed from user-land.
         *    - check the size of the argument buffer.
         *    - check the direction (IN or OUT)
-        *    - check the type (IPSec or DTLS)
+        *    - check the type (IPSec only)
         *    - crypto material direction and type must match the associated crypto context's.
         *        - we can have a list of crypto materials per context.
         * - ensure that the crypto context is already valid (don't add crypto material to invalid context).
@@ -225,13 +248,16 @@ utun_ctl_config_crypto_keys (__unused kern_ctl_ref  kctlref,
                }
 
                // branch-off for ipsec vs. dtls
+#if IPSEC
                if (crypto_keys_args->type == UTUN_CRYPTO_TYPE_IPSEC) {
                        errno_t err;
                        if ((err = utun_ctl_config_crypto_keys_ipsec(pcb, crypto_keys_args, crypto_keys))) {
                                utun_free(crypto_keys);
                                return err;
                        }
-               } else {
+               } else 
+#endif
+               {
                        // unsupported
                        utun_free(crypto_keys);
                        return EPROTONOSUPPORT;
@@ -258,7 +284,7 @@ utun_ctl_unconfig_crypto_keys (__unused kern_ctl_ref  kctlref,
         * - verify the crypto material args passed from user-land.
         *    - check the size of the argument buffer.
         *    - check the direction (IN or OUT)
-        *    - check the type (IPSec or DTLS)
+        *    - check the type (IPSec only)
         *    - crypto material direction and type must match the associated crypto context's.
         *        - we can have a list of crypto materials per context.
         * - ensure that the crypto context is already valid (don't add crypto material to invalid context).
@@ -308,6 +334,7 @@ utun_ctl_unconfig_crypto_keys (__unused kern_ctl_ref  kctlref,
                         cur_crypto_keys = nxt_crypto_keys) {
                        nxt_crypto_keys = (__typeof__(nxt_crypto_keys))LIST_NEXT(cur_crypto_keys, chain);
                        // branch-off for ipsec vs. dtls
+#if IPSEC
                        if (crypto_keys_args->type == UTUN_CRYPTO_TYPE_IPSEC) {
                                if (crypto_keys_args->u.ipsec_v1.spi == cur_crypto_keys->state.u.ipsec.spi) {
                                        errno_t err;
@@ -319,7 +346,9 @@ utun_ctl_unconfig_crypto_keys (__unused kern_ctl_ref  kctlref,
                                        utun_free(cur_crypto_keys);
                                        return 0;
                                }
-                       } else {
+                       } else 
+#endif
+                       {
                                // unsupported
                                return EPROTONOSUPPORT;
                        }
@@ -330,6 +359,151 @@ utun_ctl_unconfig_crypto_keys (__unused kern_ctl_ref  kctlref,
        return 0;
 }
 
+errno_t
+utun_ctl_config_crypto_framer (__unused kern_ctl_ref  kctlref,
+                              __unused u_int32_t     unit, 
+                              __unused void         *unitinfo,
+                              __unused int           opt, 
+                              void                  *data, 
+                              size_t                 len)
+{
+       struct utun_pcb *pcb = unitinfo;
+
+       /*
+        * - verify the crypto material args passed from user-land.
+        *    - check the size of the argument buffer.
+        *    - check the direction (IN or OUT)
+        *    - check the type (DTLS only)
+        *    - crypto material direction and type must match the associated crypto context's.
+        *        - we can have a list of crypto materials per context.
+        * - ensure that the crypto context is already valid (don't add crypto material to invalid context).
+        * - any error should be equivalent to noop.
+        */
+       if (len < UTUN_CRYPTO_FRAMER_ARGS_HDR_SIZE) {
+               return EMSGSIZE;
+       } else {
+               int                        idx;
+               utun_crypto_framer_args_t *framer_args = (__typeof__(framer_args))data;
+               utun_crypto_ctx_t         *crypto_ctx;
+
+               if (framer_args->ver == 0 || framer_args->ver >= UTUN_CRYPTO_FRAMER_ARGS_VER_MAX) {
+                       printf("%s: ver check failed %d\n", __FUNCTION__, (int)framer_args->ver);
+                       return EINVAL;
+               }
+               if (framer_args->dir == 0 || framer_args->dir >= UTUN_CRYPTO_DIR_MAX) {
+                       printf("%s: dir check failed %d\n", __FUNCTION__, (int)framer_args->dir);
+                       return EINVAL;
+               }
+               if (framer_args->type == 0 || framer_args->type >= UTUN_CRYPTO_TYPE_MAX) {
+                       printf("%s: type check failed %d\n", __FUNCTION__, (int)framer_args->type);
+                       return EINVAL;
+               }
+               if (len < UTUN_CRYPTO_FRAMER_ARGS_TOTAL_SIZE(framer_args)) {
+                       printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__,
+                              (int)len, (int)UTUN_CRYPTO_FRAMER_ARGS_TOTAL_SIZE(framer_args));
+                       return EINVAL;
+               }
+               idx = UTUN_CRYPTO_DIR_TO_IDX(framer_args->dir);
+               crypto_ctx = &pcb->utun_crypto_ctx[idx];
+               if (!crypto_ctx->valid) {
+                       return EBADF;
+               }
+               if (framer_args->type != crypto_ctx->type) {
+                       // can't add keymat to context with different crypto type
+                       return ENOENT;
+               }
+               if (framer_args->args_ulen != sizeof(framer_args->u)) {
+                       printf("%s: compatibility mode\n", __FUNCTION__);
+                       // TODO:
+               }
+
+               // branch-off for ipsec vs. dtls
+               if (framer_args->type == UTUN_CRYPTO_TYPE_DTLS) {
+                       errno_t err;
+                       if ((err = utun_ctl_config_crypto_dtls_framer(crypto_ctx, framer_args))) {
+                               return err;
+                       }
+               } else {
+                       // unsupported
+                       return EPROTONOSUPPORT;
+               }
+       }
+
+       return 0;
+}
+
+errno_t
+utun_ctl_unconfig_crypto_framer (__unused kern_ctl_ref  kctlref,
+                                __unused u_int32_t     unit, 
+                                __unused void         *unitinfo,
+                                __unused int           opt, 
+                                void                  *data, 
+                                size_t                 len)
+{
+       struct utun_pcb *pcb = unitinfo;
+
+       /*
+        * - verify the crypto material args passed from user-land.
+        *    - check the size of the argument buffer.
+        *    - check the direction (IN or OUT)
+        *    - check the type (DTLS only)
+        *    - crypto material direction and type must match the associated crypto context's.
+        *        - we can have a list of crypto materials per context.
+        * - ensure that the crypto context is already valid (don't add crypto material to invalid context).
+        * - any error should be equivalent to noop.
+        */
+       if (len < UTUN_CRYPTO_FRAMER_ARGS_HDR_SIZE) {
+               return EMSGSIZE;
+       } else {
+               int                        idx;
+               utun_crypto_framer_args_t *framer_args = (__typeof__(framer_args))data;
+               utun_crypto_ctx_t         *crypto_ctx;
+
+               if (framer_args->ver == 0 || framer_args->ver >= UTUN_CRYPTO_FRAMER_ARGS_VER_MAX) {
+                       printf("%s: ver check failed %d\n", __FUNCTION__, (int)framer_args->ver);
+                       return EINVAL;
+               }
+               if (framer_args->dir == 0 || framer_args->dir >= UTUN_CRYPTO_DIR_MAX) {
+                       printf("%s: dir check failed %d\n", __FUNCTION__, (int)framer_args->dir);
+                       return EINVAL;
+               }
+               if (framer_args->type == 0 || framer_args->type >= UTUN_CRYPTO_TYPE_MAX) {
+                       printf("%s: type check failed %d\n", __FUNCTION__, (int)framer_args->type);
+                       return EINVAL;
+               }
+               if (len < UTUN_CRYPTO_FRAMER_ARGS_TOTAL_SIZE(framer_args)) {
+                       printf("%s: vlen check failed (%d,%d)\n", __FUNCTION__,
+                                  (int)len, (int)UTUN_CRYPTO_FRAMER_ARGS_TOTAL_SIZE(framer_args));
+                       return EINVAL;
+               }
+               idx = UTUN_CRYPTO_DIR_TO_IDX(framer_args->dir);
+               crypto_ctx = &pcb->utun_crypto_ctx[idx];
+               if (!crypto_ctx->valid) {
+                       return EBADF;
+               }
+               if (framer_args->type != crypto_ctx->type) {
+                       // can't add keymat to context with different crypto type
+                       return ENOENT;
+               }
+               if (framer_args->args_ulen != sizeof(framer_args->u)) {
+                       printf("%s: compatibility mode\n", __FUNCTION__);
+               }
+
+               // branch-off for ipsec vs. dtls
+               if (framer_args->type == UTUN_CRYPTO_TYPE_DTLS) {
+                       errno_t err;
+                       if ((err = utun_ctl_unconfig_crypto_dtls_framer(crypto_ctx, framer_args))) {
+                               return err;
+                       }
+               } else {
+                       // unsupported
+                       return EPROTONOSUPPORT;
+               }
+       }
+
+       return 0;
+}
+
 errno_t
 utun_ctl_generate_crypto_keys_idx (__unused kern_ctl_ref   kctlref,
                                   __unused u_int32_t      unit, 
@@ -344,7 +518,7 @@ utun_ctl_generate_crypto_keys_idx (__unused kern_ctl_ref   kctlref,
         * - verify the crypto material index args passed from user-land.
         *    - check the size of the argument buffer.
         *    - check the direction (IN or OUT)
-        *    - check the type (IPSec or DTLS)
+        *    - check the type (IPSec only)
         *    - crypto material direction and type must match the associated crypto context's.
         *        - we can have a list of crypto materials per context.
         * - any error should be equivalent to noop.
@@ -388,12 +562,15 @@ utun_ctl_generate_crypto_keys_idx (__unused kern_ctl_ref   kctlref,
 
                // traverse crypto materials looking for the right one
                // branch-off for ipsec vs. dtls
+#if IPSEC
                if (crypto_keys_idx_args->type == UTUN_CRYPTO_TYPE_IPSEC) {
                        errno_t err;
                        if ((err = utun_ctl_generate_crypto_keys_idx_ipsec(crypto_keys_idx_args))) {
                                return err;
                        }
-               } else {
+               } else 
+#endif
+               {
                        // unsupported
                        return EPROTONOSUPPORT;
                }
@@ -449,7 +626,11 @@ utun_ctl_stop_crypto_data_traffic (__unused kern_ctl_ref  kctlref,
                        return EINVAL;
                }
 
-               if (crypto_args->type != UTUN_CRYPTO_TYPE_IPSEC) {
+               if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) {
+                       // nothing
+               } else if (crypto_args->type == UTUN_CRYPTO_TYPE_DTLS) {
+                       utun_ctl_stop_datatraffic_crypto_dtls(pcb);
+               } else {
                        // unsupported
                        return EPROTONOSUPPORT;
                }
@@ -505,7 +686,11 @@ utun_ctl_start_crypto_data_traffic (__unused kern_ctl_ref  kctlref,
                        return EINVAL;
                }
 
-               if (crypto_args->type != UTUN_CRYPTO_TYPE_IPSEC) {
+               if (crypto_args->type == UTUN_CRYPTO_TYPE_IPSEC) {
+                       // nothing
+               } else if (crypto_args->type == UTUN_CRYPTO_TYPE_DTLS) {
+                       utun_ctl_start_datatraffic_crypto_dtls(pcb);
+               } else {
                        // unsupported
                        return EPROTONOSUPPORT;
                }
@@ -522,8 +707,13 @@ utun_pkt_crypto_output (struct utun_pcb *pcb, mbuf_t *m)
                printf("%s: context is invalid %d\n", __FUNCTION__, pcb->utun_crypto_ctx[idx].valid);
                return -1;
        }
+#if IPSEC
        if (pcb->utun_crypto_ctx[idx].type ==  UTUN_CRYPTO_TYPE_IPSEC) {
                return(utun_pkt_ipsec_output(pcb, m));
+       } else 
+#endif
+       if (pcb->utun_crypto_ctx[idx].type ==  UTUN_CRYPTO_TYPE_DTLS) {
+               return(utun_pkt_dtls_output(pcb, m));
        } else {
                // unsupported
                printf("%s: type is invalid %d\n", __FUNCTION__, pcb->utun_crypto_ctx[idx].type);