On Wed, Jul 12, 2017 at 01:45:36PM +1000, David Gwynne wrote:
> On Tue, Jul 11, 2017 at 11:48:47AM +0000, Florian Obser wrote:
> > On Tue, Jul 11, 2017 at 11:08:23AM +0100, Stuart Henderson wrote:
> > > On 2017/07/11 07:45, Florian Obser wrote:
> > > > 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)
> > >
> > > It's slightly different to autoconfprivacy as that is enabled by
> > > default in the kernel for new interfaces, whereas with this it depends
> > > on the key being configured. So there are implications for dynamically
> > > created interfaces (USB, vlan etc) which may not always be handled by
> > > netstart.
> > >
> > > I'm wondering if we should have a "system soiikey" (e.g. in a sysctl)
> > > that is automatically applied to newly created interfaces? (Does the
> > > key even need to be configurable per-interface or would a per-system
> > > one be enough by itself?)
> >
> > I was also considering this. A per system key is probably enough. I
> > went with the per-interface key because that made it easier to disable
> > the feature on an interface. If we go with per-system we need a
> > interface flag to disable the feature (like -autoconfprivacy).
> >
> > The rfc seems to assume a per system secret.
> >
> > hmm... are there sysctls that are only readable as root?
>
> yeah. see below for example code for a net.inet6.ip6.soiikey sysctl.
> it looks big cos it teaches sysctl how to handle binary strings
> represented by hex.
Awesome, thank you very much, I will adapt my diff to this.
I don't think that we need to check securelevel (re: your comment in
the diff).
I don't really believe in securelevel, also it seems that even at 2
you are still allowed to change ip addresses on interfaces. And this
is all this key influences. Additionally I think it is valid to change
the key during runtime.
>
> are we tied to sha512 for this? siphash makes a nice 8 byte output...
Nope, the rfc intentionally does not specify the hash function.
>
> >
> > >
> > > > 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?
> > >
> > > A couple of other comments:
> > >
> > > - system administrators should know in advance of updating that their
> > > IP address may change in case they need to prepare for it (adjust
> > > firewalls/nat-pt/proxies).
> >
> > sure, /me glances at current.html
> >
> > >
> > > - ramdisk upgrades may need to load the key from the installed system
> > > (e.g. in presence of restrictive firewall policies).
> > >
> >
> > good point
> >
> > > - a half-related idea came up while pondering this,
> > > "block in inet6 to autoconfprivacy" (similar UI to urpf-failed)
> > > (I'm meant to be doing something else and likely to forget so I'd
> > > like to at least plant the idea :)
> >
> > heh, interesting
> >
> > --
> > I'm not entirely sure you are real.
>
>
> Index: sbin/sysctl/sysctl.c
> ===================================================================
> RCS file: /cvs/src/sbin/sysctl/sysctl.c,v
> retrieving revision 1.226
> diff -u -p -r1.226 sysctl.c
> --- sbin/sysctl/sysctl.c 25 Apr 2017 17:33:16 -0000 1.226
> +++ sbin/sysctl/sysctl.c 12 Jul 2017 03:39:33 -0000
> @@ -212,7 +212,7 @@ int sysctl_chipset(char *, char **, int
> #endif
> void vfsinit(void);
>
> -char *equ = "=";
> +const char *equ = "=";
>
> int
> main(int argc, char *argv[])
> @@ -286,6 +286,52 @@ listall(char *prefix, struct list *lp)
> }
> }
>
> +int
> +parse_hex_char(char ch)
> +{
> + if (ch >= '0' && ch <= '9')
> + return (ch - '0');
> + if (ch >= 'a' && ch <= 'f')
> + return (ch - 'a');
> + if (ch >= 'A' && ch <= 'F')
> + return (ch - 'A');
> +
> + return (-1);
> +}
> +
> +ssize_t
> +parse_hex_string(unsigned char *dst, size_t dstlen, const char *src)
> +{
> + ssize_t len = 0;
> + int digit;
> +
> + while (len < dstlen) {
> + if (*src == '\0')
> + return (len);
> +
> + digit = parse_hex_char(*src++);
> + if (digit == -1)
> + return (-1);
> + dst[len] = digit << 4;
> +
> + digit = parse_hex_char(*src++);
> + if (digit == -1)
> + return (-1);
> +
> + dst[len] |= digit;
> + len++;
> + }
> +
> + while (*src != '\0') {
> + if (parse_hex_char(*src++) == -1 ||
> + parse_hex_char(*src++) == -1)
> + return (-1);
> + len++;
> + }
> +
> + return (len);
> +}
> +
> /*
> * Parse a name into a MIB entry.
> * Lookup and print out the MIB entry if it exists.
> @@ -566,6 +612,9 @@ parse(char *string, int flags)
> len = sysctl_inet6(string, &bufp, mib, flags, &type);
> if (len < 0)
> return;
> + if (mib[2] == IPPROTO_IPV6 &&
> + mib[3] == IPV6CTL_SOIIKEY)
> + special |= HEX;
>
> if ((mib[2] == IPPROTO_IPV6 && mib[3] ==
> IPV6CTL_MRTMFC) ||
> (mib[2] == IPPROTO_IPV6 && mib[3] ==
> IPV6CTL_MRTMIF) ||
> @@ -717,6 +766,29 @@ parse(char *string, int flags)
> newval = &quadval;
> newsize = sizeof(quadval);
> break;
> + case CTLTYPE_STRING:
> + if (special & HEX) {
> + ssize_t len;
> +
> + len = parse_hex_string(buf, sizeof(buf),
> + newval);
> + if (len == -1) {
> + warnx("%s: hex string %s: invalid",
> + string, newval);
> + return;
> + }
> + if (len > sizeof(buf)) {
> + warnx("%s: hex string %s: too long",
> + string, newval);
> + return;
> + }
> +
> + newval = buf;
> + newsize = len;
> +
> + printf("newsize = %zu\n", newsize);
> + }
> + break;
> }
> }
> size = (special & SMALLBUF) ? 512 : SYSCTL_BUFSIZ;
> @@ -936,13 +1008,26 @@ parse(char *string, int flags)
> if (newval == NULL) {
> if (!nflag)
> (void)printf("%s%s", string, equ);
> - (void)puts(buf);
> - } else {
> - if (!qflag) {
> - if (!nflag)
> - (void)printf("%s: %s -> ", string, buf);
> - (void)puts((char *)newval);
> + if (special & HEX) {
> + size_t i;
> + for (i = 0; i < size; i++)
> + (void)printf("%02x", buf[i]);
> + (void)printf("\n");
> + } else
> + (void)puts(buf);
> + } else if (!qflag) {
> + if (!nflag) {
> + (void)printf("%s: ", string);
> + if (special & HEX) {
> + size_t i;
> + for (i = 0; i < size; i++)
> + (void)printf("%02x", buf[i]);
> + } else
> + (void)printf("%s", cp);
> +
> + (void)printf(" -> ");
> }
> + (void)puts(cp);
> }
> return;
>
> Index: sys/netinet6/in6.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/in6.h,v
> retrieving revision 1.96
> diff -u -p -r1.96 in6.h
> --- sys/netinet6/in6.h 30 May 2017 09:10:49 -0000 1.96
> +++ sys/netinet6/in6.h 12 Jul 2017 03:39:33 -0000
> @@ -592,7 +592,8 @@ ifatoia6(struct ifaddr *ifa)
> #define IPV6CTL_IFQUEUE 51
> #define IPV6CTL_MRTMIF 52
> #define IPV6CTL_MRTMFC 53
> -#define IPV6CTL_MAXID 54
> +#define IPV6CTL_SOIIKEY 54
> +#define IPV6CTL_MAXID 55
>
> /* New entries should be added here from current IPV6CTL_MAXID value. */
> /* to define items, should talk with KAME guys first, for *BSD compatibility
> */
> @@ -652,6 +653,7 @@ ifatoia6(struct ifaddr *ifa)
> { "ifq", CTLTYPE_NODE }, \
> { "mrtmif", CTLTYPE_STRUCT }, \
> { "mrtmfc", CTLTYPE_STRUCT }, \
> + { "soiikey", CTLTYPE_STRING }, /* binary string */ \
> }
>
> #define IPV6CTL_VARS { \
> Index: sys/netinet6/ip6_input.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
> retrieving revision 1.198
> diff -u -p -r1.198 ip6_input.c
> --- sys/netinet6/ip6_input.c 5 Jul 2017 11:34:10 -0000 1.198
> +++ sys/netinet6/ip6_input.c 12 Jul 2017 03:39:34 -0000
> @@ -1375,6 +1375,56 @@ ip6_sysctl_ip6stat(void *oldp, size_t *o
> return (ret);
> }
>
> +struct ip6_soiikey {
> + unsigned int len;
> + unsigned char key[32];
> +};
> +
> +struct ip6_soiikey ip6_soiikey = { .len = 0 };
> +
> +int
> +ip6_sysctl_soiikey(void *oldp, size_t *oldlenp, void *newp, size_t newlen)
> +{
> + unsigned char key[32];
> + int error;
> +
> + error = suser(curproc, 0);
> + if (error != 0)
> + return (error);
> +
> + if (oldp != NULL) {
> + if (newp == NULL && ip6_soiikey.len == 0)
> + return (EOPNOTSUPP);
> + if (*oldlenp < ip6_soiikey.len)
> + return (ENOMEM);
> + }
> + if (newp != NULL) {
> + /* check securelevel? */
> + if (newlen > sizeof(ip6_soiikey.key))
> + return (EINVAL);
> + if (newlen > 0) {
> + error = copyin(newp, key, newlen);
> + if (error != 0)
> + return (error);
> + }
> + }
> + if (oldp != NULL) {
> + error = copyout(ip6_soiikey.key, oldp, *oldlenp);
> + if (error != 0)
> + return (error);
> + *oldlenp = ip6_soiikey.len;
> + }
> +
> + if (newp != NULL) {
> + /* commit */
> + if (newlen > 0)
> + memcpy(ip6_soiikey.key, key, newlen);
> + ip6_soiikey.len = newlen;
> + }
> +
> + return (0);
> +}
> +
> int
> ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
> void *newp, size_t newlen)
> @@ -1429,6 +1479,8 @@ ip6_sysctl(int *name, u_int namelen, voi
> case IPV6CTL_IFQUEUE:
> return (sysctl_niq(name + 1, namelen - 1,
> oldp, oldlenp, newp, newlen, &ip6intrq));
> + case IPV6CTL_SOIIKEY:
> + return (ip6_sysctl_soiikey(oldp, oldlenp, newp, newlen));
> default:
> if (name[0] < IPV6CTL_MAXID)
> return (sysctl_int_arr(ipv6ctl_vars, name, namelen,
>
--
I'm not entirely sure you are real.