golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/tunnel/deterministicguid.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package tunnel
     7  
     8  import (
     9  	"bytes"
    10  	"encoding/binary"
    11  	"sort"
    12  	"unsafe"
    13  
    14  	"golang.org/x/crypto/blake2s"
    15  	"golang.org/x/sys/windows"
    16  	"golang.org/x/text/unicode/norm"
    17  
    18  	"golang.zx2c4.com/wireguard/windows/conf"
    19  )
    20  
    21  const (
    22  	deterministicGUIDLabel = "Deterministic WireGuard Windows GUID v1 jason@zx2c4.com"
    23  	fixedGUIDLabel         = "Fixed WireGuard Windows GUID v1 jason@zx2c4.com"
    24  )
    25  
    26  // Escape hatch for external consumers, not us.
    27  var UseFixedGUIDInsteadOfDeterministic = false
    28  
    29  /* All peer public keys and allowed ips are sorted. Length/number fields are
    30   * little endian 32-bit. Hash input is:
    31   *
    32   * label || len(interface name) || interface name ||
    33   * interface public key || number of peers ||
    34   * peer public key || number of peer allowed ips ||
    35   * len(allowed ip string) || allowed ip/cidr in canonical string notation ||
    36   * len(allowed ip string) || allowed ip/cidr in canonical string notation ||
    37   * len(allowed ip string) || allowed ip/cidr in canonical string notation ||
    38   * ...
    39   * peer public key || number of peer allowed ips ||
    40   * len(allowed ip string) || allowed ip/cidr in canonical string notation ||
    41   * len(allowed ip string) || allowed ip/cidr in canonical string notation ||
    42   * len(allowed ip string) || allowed ip/cidr in canonical string notation ||
    43   * ...
    44   * ...
    45   */
    46  
    47  func deterministicGUID(c *conf.Config) *windows.GUID {
    48  	b2, _ := blake2s.New256(nil)
    49  	if !UseFixedGUIDInsteadOfDeterministic {
    50  		b2.Write([]byte(deterministicGUIDLabel))
    51  	} else {
    52  		b2.Write([]byte(fixedGUIDLabel))
    53  	}
    54  	b2Number := func(i int) {
    55  		if uint(i) > uint(^uint32(0)) {
    56  			panic("length out of bounds")
    57  		}
    58  		var bytes [4]byte
    59  		binary.LittleEndian.PutUint32(bytes[:], uint32(i))
    60  		b2.Write(bytes[:])
    61  	}
    62  	b2String := func(s string) {
    63  		bytes := []byte(s)
    64  		bytes = norm.NFC.Bytes(bytes)
    65  		b2Number(len(bytes))
    66  		b2.Write(bytes)
    67  	}
    68  	b2Key := func(k *conf.Key) {
    69  		b2.Write(k[:])
    70  	}
    71  
    72  	b2String(c.Name)
    73  	if !UseFixedGUIDInsteadOfDeterministic {
    74  		b2Key(c.Interface.PrivateKey.Public())
    75  		b2Number(len(c.Peers))
    76  		sortedPeers := c.Peers
    77  		sort.Slice(sortedPeers, func(i, j int) bool {
    78  			return bytes.Compare(sortedPeers[i].PublicKey[:], sortedPeers[j].PublicKey[:]) < 0
    79  		})
    80  		for _, peer := range sortedPeers {
    81  			b2Key(&peer.PublicKey)
    82  			b2Number(len(peer.AllowedIPs))
    83  			sortedAllowedIPs := peer.AllowedIPs
    84  			sort.Slice(sortedAllowedIPs, func(i, j int) bool {
    85  				if bi, bj := sortedAllowedIPs[i].Addr().BitLen(), sortedAllowedIPs[j].Addr().BitLen(); bi != bj {
    86  					return bi < bj
    87  				}
    88  				if sortedAllowedIPs[i].Bits() != sortedAllowedIPs[j].Bits() {
    89  					return sortedAllowedIPs[i].Bits() < sortedAllowedIPs[j].Bits()
    90  				}
    91  				return sortedAllowedIPs[i].Addr().Compare(sortedAllowedIPs[j].Addr()) < 0
    92  			})
    93  			for _, allowedip := range sortedAllowedIPs {
    94  				b2String(allowedip.String())
    95  			}
    96  		}
    97  	}
    98  	return (*windows.GUID)(unsafe.Pointer(&b2.Sum(nil)[0]))
    99  }