aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tunnel/deterministicguid.go
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-06-09 19:37:09 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-06-10 11:38:22 +0200
commit5ced3852cedfd863d8736a1a441cc2c68ce48e3c (patch)
treef02e09e5da87e18daa014303b686e460a03010b8 /tunnel/deterministicguid.go
parentmod: bump wireguard-go (diff)
downloadwireguard-windows-5ced3852cedfd863d8736a1a441cc2c68ce48e3c.tar.xz
wireguard-windows-5ced3852cedfd863d8736a1a441cc2c68ce48e3c.zip
tunnel: generate GUIDs deterministically
This allows NLA profiles to securely bind public keys to firewall profiles, a considerable improvement on the usual insecure Windows situation.
Diffstat (limited to 'tunnel/deterministicguid.go')
-rw-r--r--tunnel/deterministicguid.go73
1 files changed, 73 insertions, 0 deletions
diff --git a/tunnel/deterministicguid.go b/tunnel/deterministicguid.go
new file mode 100644
index 00000000..720972bf
--- /dev/null
+++ b/tunnel/deterministicguid.go
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: MIT
+ *
+ * Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
+ */
+
+package tunnel
+
+import (
+ "bytes"
+ "encoding/binary"
+ "sort"
+ "unsafe"
+
+ "golang.org/x/crypto/blake2s"
+ "golang.org/x/sys/windows"
+
+ "golang.zx2c4.com/wireguard/windows/conf"
+)
+
+const deterministicGUIDLabel = "Deterministic WireGuard Windows GUID for interface: "
+
+/* All peer public keys and allowed ips are sorted. Hash input is:
+ *
+ * label || interface name || zero padding to blake2s blocksize ||
+ * interface public key ||
+ * little endian 32-bit number of peers ||
+ * peer public key || little endian 32-bit number of peer allowed ips ||
+ * allowed ip in canonical string notation || '/' || cidr in decimal || '\n' ||
+ * allowed ip in canonical string notation || '/' || cidr in decimal || '\n' ||
+ * ...
+ * peer public key || little endian 32-bit number of peer allowed ips ||
+ * allowed ip in canonical string notation || '/' || cidr in decimal || '\n' ||
+ * allowed ip in canonical string notation || '/' || cidr in decimal || '\n' ||
+ * ...
+ * ...
+ */
+
+func deterministicGUID(conf *conf.Config) *windows.GUID {
+ b2, _ := blake2s.New256(nil)
+ u32 := func(i uint32) {
+ var bytes [4]byte
+ binary.LittleEndian.PutUint32(bytes[:], i)
+ b2.Write(bytes[:])
+ }
+ header := []byte(deterministicGUIDLabel)
+ header = append(header, []byte(conf.Name)...)
+ b2.Write(header)
+ b2.Write(make([]byte, (((len(header)-1)|(blake2s.BlockSize-1))+1)-len(header)))
+ b2.Write(conf.Interface.PrivateKey.Public()[:])
+ u32(uint32(len(conf.Peers)))
+ sortedPeers := conf.Peers
+ sort.Slice(sortedPeers, func(i, j int) bool {
+ return bytes.Compare(sortedPeers[i].PublicKey[:], sortedPeers[j].PublicKey[:]) < 0
+ })
+ for _, peer := range sortedPeers {
+ b2.Write(peer.PublicKey[:])
+ u32(uint32(len(peer.AllowedIPs)))
+ sortedAllowedIPs := peer.AllowedIPs
+ sort.Slice(sortedAllowedIPs, func(i, j int) bool {
+ if bi, bj := sortedAllowedIPs[i].Bits(), sortedAllowedIPs[j].Bits(); bi != bj {
+ return bi < bj
+ }
+ if sortedAllowedIPs[i].Cidr != sortedAllowedIPs[j].Cidr {
+ return sortedAllowedIPs[i].Cidr < sortedAllowedIPs[j].Cidr
+ }
+ return bytes.Compare(sortedAllowedIPs[i].IP[:], sortedAllowedIPs[j].IP[:]) < 0
+ })
+ for _, allowedip := range sortedAllowedIPs {
+ b2.Write([]byte(allowedip.String() + "\n"))
+ }
+ }
+ return (*windows.GUID)(unsafe.Pointer(&b2.Sum(nil)[0]))
+}