Here is the first step in implementing RFC 7217 "A Method for
Generating Semantically Opaque Interface Identifiers with IPv6
Stateless Address Autoconfiguration (SLAAC)"

This is orthogonal to privacy extension. The idea is to replace the
stable slaac addresses formed from the MAC address of your ethernet
device with a random but stable over reboots address. This address can
be used for server type services to connect in since the address is
stable over reboots. It defends against certain scanning and
enumeration attacks since it's random. See the RFC for details.

The way I want to move forward with this is:

1) generate a random key at boot if it's not present yet (like we do
for ssh host keys and ipsec)
2) if /etc/netstart brings up an interface set the key there by
enabling the feature per default like we do with privacy addresses.
NOTE that this does NOT enable v6.
If you do not want this you have to put -soiikey into the hostname.if
file (like -autoconfprivacy)
3) if v6 is enabled in hostname.if you get a random but stable link
local address according to RFC 7217.
4) if autoconf6 is enabled on the interface slaacd will generate a
random but stable global address according to RFC 7217

Also note that RFC 8064 is a thing and we are kinda supposed to do this.
Also I think it's a good idea[tm].

Comments, OKs?

diff --git sbin/ifconfig/ifconfig.8 sbin/ifconfig/ifconfig.8
index cac8eafc2cb..584a90911f4 100644
--- sbin/ifconfig/ifconfig.8
+++ sbin/ifconfig/ifconfig.8
@@ -1070,6 +1070,7 @@ protocol when supported by the access point.
 .Op Oo Fl Oc Ns Cm autoconfprivacy
 .Op Cm eui64
 .Op Cm pltime Ar n
+.Op Oo Fl Oc Ns Cm soiikey Ar hexkey
 .Op Oo Fl Oc Ns Cm tentative
 .Op Cm vltime Ar n
 .Ek
@@ -1127,6 +1128,18 @@ Fill the interface index
 automatically.
 .It Cm pltime Ar n
 Set preferred lifetime for the address.
+.It Cm soiikey Ar hexkey
+Set the secret to generate random but stable Semantically Opaque
+Interface Identifiers (RFC 7217) for IPv6 Stateless Address
+Autoconfiguration.
+This is orthogonal to
+.Cm autoconfprivacy .
+It is meant to improve the security and privacy properties of the
+stable addresses formed from the layer 2 hardware address by replacing
+them with a random but stable address that depends on the advertised
+prefix.
+.It Cm -soikey
+Disable generation of Semantically Opaque Interface Identifiers. 
 .It Cm tentative
 Set the IPv6 tentative address bit.
 .It Cm -tentative
diff --git sbin/ifconfig/ifconfig.c sbin/ifconfig/ifconfig.c
index d99bcb34871..b08dbe57d83 100644
--- sbin/ifconfig/ifconfig.c
+++ sbin/ifconfig/ifconfig.c
@@ -198,6 +198,7 @@ void        setia6pltime(const char *, int);
 void   setia6vltime(const char *, int);
 void   setia6lifetime(const char *, const char *);
 void   setia6eui64(const char *, int);
+void   setifsoiikey(const char *, int);
 void   setkeepalive(const char *, const char *);
 void   unsetkeepalive(const char *, int);
 void   setmedia(const char *, int);
@@ -376,6 +377,8 @@ const struct        cmd {
        { "-group",     NEXTARG,        0,              unsetifgroup },
        { "autoconf",   1,              0,              setautoconf },
        { "-autoconf",  -1,             0,              setautoconf },
+       { "soiikey",    NEXTARG,        0,              setifsoiikey },
+       { "-soiikey",   -1,             0,              setifsoiikey },
        { "trunkport",  NEXTARG,        0,              settrunkport },
        { "-trunkport", NEXTARG,        0,              unsettrunkport },
        { "trunkproto", NEXTARG,        0,              settrunkproto },
@@ -1418,6 +1421,36 @@ setautoconf(const char *cmd, int val)
        }
 }
 
+void
+setifsoiikey(const char *val, int d)
+{
+       struct if_soiikey soiikey;
+       int passlen;
+
+       memset(&soiikey, 0, sizeof(soiikey));
+       if (d != -1) {
+               passlen = strlen(val);
+
+               if (passlen < 4 || (passlen - 2) % 2 != 0 ||
+                   val[0] != '0' || val[1] != 'x')
+                       errx(1, "soiikey: invalid key");
+
+               soiikey.len = (passlen - 2) / 2;
+
+               val = get_string(val, NULL, soiikey.key, &passlen);
+               if (val == NULL)
+                       errx(1, "soiikey: invalid soii key");
+
+               soiikey.enabled = 1;
+       } else
+               soiikey.enabled = 0;
+
+       ifr.ifr_data = (caddr_t)&soiikey;
+
+       if (ioctl(s, SIOCSIFSOIIKEY, (caddr_t)&ifr) < 0)
+               err(1, "SIOCSIFSOIIKEY");
+}
+
 #ifndef SMALL
 /* ARGSUSED */
 void
@@ -2838,6 +2871,7 @@ status(int link, struct sockaddr_dl *sdl, int ls)
 {
        const struct afswtch *p = afp;
        struct ifmediareq ifmr;
+       struct if_soiikey soiikey;
 #ifndef SMALL
        struct ifreq ifrdesc;
        struct ifkalivereq ikardesc;
@@ -2982,6 +3016,24 @@ status(int link, struct sockaddr_dl *sdl, int ls)
                putchar('\n');
        }
 #endif
+
+       memset(&soiikey, 0, sizeof(soiikey));
+       ifr.ifr_data = (caddr_t)&soiikey;
+       if (ioctl(s, SIOCGIFSOIIKEY, (caddr_t)&ifr) == -1)
+               err(1, "SIOCGIFSOIIKEY: %lu", SIOCGIFSOIIKEY);
+       if (soiikey.enabled) {
+               printf("\tsoiikey: ");
+               if (soiikey.enabled == 2)
+                       fputs("<not displayed>", stdout);
+               else {
+                       if (soiikey.len <= sizeof(soiikey))
+                               print_string(soiikey.key, soiikey.len);
+                       else
+                               fputs("<invalid>", stdout);
+               }
+               printf("\n");
+       }
+
        ieee80211_status();
 
        if (showmediaflag) {
diff --git sys/net/if.c sys/net/if.c
index 6354484e477..1e323a37fb2 100644
--- sys/net/if.c
+++ sys/net/if.c
@@ -163,6 +163,10 @@ void       ifa_print_all(void);
 
 void   if_qstart_compat(struct ifqueue *);
 
+#ifdef INET6
+void   ifnewsoiikey(struct ifnet *);
+#endif
+
 /*
  * interface index map
  *
@@ -1824,6 +1828,9 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, 
struct proc *p)
        struct sockaddr_dl *sdl;
        struct ifgroupreq *ifgr;
        struct if_afreq *ifar;
+#ifdef INET6
+       struct if_soiikey *soiikey;
+#endif
        char ifdescrbuf[IFDESCRSIZE];
        char ifrtlabelbuf[RTLABEL_LEN];
        int s, error = 0;
@@ -2185,6 +2192,40 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, 
struct proc *p)
                ifp->if_llprio = ifr->ifr_llprio;
                break;
 
+#ifdef INET6
+       case SIOCGIFSOIIKEY:
+               soiikey = (struct if_soiikey *)ifr->ifr_data;
+               if (ifp->if_soiikey.enabled) {
+                       soiikey->enabled = 1;
+                       if (suser(curproc, 0) != 0) {
+                               soiikey->enabled = 2;
+                               memset(soiikey->key, 0, sizeof(soiikey->key));
+                               break;  /* return ok but w/o key */
+                       }
+                       memcpy(soiikey->key, ifp->if_soiikey.key,
+                           sizeof(soiikey->key));
+                       soiikey->len = ifp->if_soiikey.len;
+               } else
+                       soiikey->enabled = 0;
+               break;
+       case SIOCSIFSOIIKEY:
+               if ((error = suser(curproc, 0)) != 0)
+                       break;
+               soiikey = (struct if_soiikey *)ifr->ifr_data;
+               if (soiikey->enabled) {
+                       if (soiikey->len > sizeof(soiikey->key)) {
+                               error = EINVAL;
+                               break;
+                       }
+                       ifp->if_soiikey.len = soiikey->len;
+                       memcpy(&ifp->if_soiikey, soiikey,
+                           sizeof(ifp->if_soiikey));
+               } else
+                       memset(&ifp->if_soiikey, 0, sizeof(ifp->if_soiikey));
+               ifnewsoiikey(ifp);
+               break;
+#endif /* INET6 */
+
        default:
                if (so->so_proto == 0)
                        return (EOPNOTSUPP);
@@ -2798,6 +2839,28 @@ ifnewlladdr(struct ifnet *ifp)
        splx(s);
 }
 
+#ifdef INET6
+void
+ifnewsoiikey(struct ifnet *ifp)
+{
+       struct ifaddr *ifa;
+       int s;
+
+       s = splnet();
+
+       /*
+        * Update the link-local address.
+        */
+       ifa = &in6ifa_ifpforlinklocal(ifp, 0)->ia_ifa;
+       if (ifa) {
+               in6_purgeaddr(ifa);
+               dohooks(ifp->if_addrhooks, 0);
+               in6_ifattach(ifp);
+       }
+       splx(s);
+}
+#endif /* INET6 */
+
 int net_ticks;
 u_int net_livelocks;
 
diff --git sys/net/if.h sys/net/if.h
index 89867eac340..5ab6f2f5417 100644
--- sys/net/if.h
+++ sys/net/if.h
@@ -452,6 +452,13 @@ struct if_parent {
        char            ifp_parent[IFNAMSIZ];
 };
 
+/* SIOC[SG]IFSOIIKEY */
+struct if_soiikey {
+       int     enabled;
+       int     len;
+       uint8_t key[32];
+};
+
 #include <net/if_arp.h>
 
 #ifdef _KERNEL
diff --git sys/net/if_var.h sys/net/if_var.h
index 14e118bcbef..5e33fa2a59f 100644
--- sys/net/if_var.h
+++ sys/net/if_var.h
@@ -130,6 +130,9 @@ struct ifnet {                              /* and the 
entries */
        unsigned short if_flags;        /* up/down, broadcast, etc. */
        int     if_xflags;              /* extra softnet flags */
        struct  if_data if_data;        /* stats and other data about if */
+#ifdef INET6
+       struct if_soiikey if_soiikey;
+#endif
        u_int32_t if_hardmtu;           /* maximum MTU device supports */
        char    if_description[IFDESCRSIZE]; /* interface description */
        u_short if_rtlabelid;           /* next route label */
diff --git sys/netinet6/in6_ifattach.c sys/netinet6/in6_ifattach.c
index fad1eb130b6..d8af7e69ccc 100644
--- sys/netinet6/in6_ifattach.c
+++ sys/netinet6/in6_ifattach.c
@@ -58,6 +58,7 @@
 
 int get_last_resort_ifid(struct ifnet *, struct in6_addr *);
 int get_hw_ifid(struct ifnet *, struct in6_addr *);
+int get_soii_ifid(struct ifnet *, struct in6_addr *);
 int get_ifid(struct ifnet *, struct in6_addr *);
 int in6_ifattach_loopback(struct ifnet *);
 
@@ -231,6 +232,55 @@ get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
 }
 
 /*
+ * Generate a Semantically Opaque Interface Identifier according to RFC 7217
+ *
+ * in6 - upper 64bits are preserved
+ */
+int
+get_soii_ifid(struct ifnet *ifp, struct in6_addr *in6)
+{
+       SHA2_CTX ctx;
+       struct in6_addr prefix;
+       struct sockaddr_dl *sdl;
+       int dad_counter = 0; /* XXX not used */
+       char *addr;
+       u_int8_t digest[SHA512_DIGEST_LENGTH];
+
+       if (!ifp->if_soiikey.enabled || ifp->if_soiikey.len <= 0)
+               return -1;
+
+       sdl = ifp->if_sadl;
+       if (sdl == NULL || sdl->sdl_alen == 0)
+               return -1;
+
+       memset(&prefix, 0, sizeof(prefix));
+       prefix.s6_addr16[0] = htons(0xfe80);
+       addr = LLADDR(sdl);
+
+       SHA512Init(&ctx);
+       SHA512Update(&ctx, &prefix, sizeof(prefix));
+       SHA512Update(&ctx, addr, sdl->sdl_alen);
+       SHA512Update(&ctx, &dad_counter, sizeof(dad_counter));
+       SHA512Update(&ctx, &dad_counter, sizeof(dad_counter));
+       SHA512Update(&ctx, ifp->if_soiikey.key, ifp->if_soiikey.len);
+
+       SHA512Final(digest, &ctx);
+
+       /* assumes sizeof(digest) > sizeof(ifid) */
+       bcopy(digest, &in6->s6_addr[8], 8);
+
+       /* make sure to set "u" bit to local, and "g" bit to individual. */
+       in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
+       in6->s6_addr[8] |= EUI64_UBIT;  /* u bit to "local" */
+
+       /* convert EUI64 into IPv6 interface identifier */
+       EUI64_TO_IFID(in6);
+
+       return 0;
+}
+
+
+/*
  * Get interface identifier for the specified interface.  If it is not
  * available on ifp0, borrow interface identifier from other information
  * sources.
@@ -240,7 +290,15 @@ get_ifid(struct ifnet *ifp0, struct in6_addr *in6)
 {
        struct ifnet *ifp;
 
-       /* first, try to get it from the interface itself */
+       /* first, try to generate a Semantically Opaque Interface Identifier */
+       if (get_soii_ifid(ifp0, in6) == 0) {
+               nd6log((LOG_DEBUG, "%s: got Semantically Opaque Interface "
+                   "Identifier\n",
+                   ifp0->if_xname));
+               goto success;
+       }
+
+       /* next, try to get it from the interface itself */
        if (get_hw_ifid(ifp0, in6) == 0) {
                nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
                    ifp0->if_xname));
diff --git sys/sys/sockio.h sys/sys/sockio.h
index 216c2d5ba31..0fa64195c0a 100644
--- sys/sys/sockio.h
+++ sys/sys/sockio.h
@@ -208,6 +208,9 @@
 #define        SIOCSUMBPARAM    _IOW('i', 191, struct ifreq)   /* set MBIM 
param */
 #define        SIOCGUMBPARAM   _IOWR('i', 192, struct ifreq)   /* get MBIM 
param */
 
+#define        SIOCSIFSOIIKEY   _IOW('i', 193, struct ifreq)   /* set soiikey 
*/
+#define        SIOCGIFSOIIKEY  _IOWR('i', 194, struct ifreq)   /* get soiikey 
*/
+
 #define        SIOCSVH         _IOWR('i', 245, struct ifreq)   /* set carp 
param */
 #define        SIOCGVH         _IOWR('i', 246, struct ifreq)   /* get carp 
param */
 


-- 
I'm not entirely sure you are real.

Reply via email to