aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tunnel/deterministicguid.go
blob: 720972bf68d4e995f7eaeb45ecd779c34aa9a2d6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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]))
}