Skip to content

Commit

Permalink
ipsec: fix per-node-pair-key computation
Browse files Browse the repository at this point in the history
This commit ensures that

- each time we compute a per-node-pair-key we create an empty slice with
  the correct length first, and then append all the input data instead
  of appending to one of the input slices (`globalKey`) directly.
- the IPs that are used as arguments in `computeNodeIPsecKey` are
  canonical, meaning IPv4 IPs consist of 4 bytes and IPv6 IPs consist of
  16 bytes.

This is necessary to always have the same inputs on all nodes when
computing the per-node-pair-key. Without this IPs might not match on the
byte level, e.g on one node the input is a v6 mapped v4 address (IPv4
address in 16 bytes) and on the other it isn't when used as input to the
hash function. This will generate non-matching keys.

Co-authored-by: Zhichuan Liang <gray.liang@isovalent.com>
Signed-off-by: Robin Gögge <r.goegge@gmail.com>
  • Loading branch information
2 people authored and aanm committed Mar 26, 2024
1 parent 5b04f09 commit a652c12
Showing 1 changed file with 18 additions and 3 deletions.
21 changes: 18 additions & 3 deletions pkg/datapath/linux/ipsec/ipsec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,26 @@ func getGlobalIPsecKey(ip net.IP) *ipSecKey {
// pre-shared key. The per-node-pair keys are computed with a SHA256 hash of
// the global key, source node IP, destination node IP appended together.
func computeNodeIPsecKey(globalKey, srcNodeIP, dstNodeIP, srcBootID, dstBootID []byte) []byte {
input := append(globalKey, srcNodeIP...)
inputLen := len(globalKey) + len(srcNodeIP) + len(dstNodeIP) + len(srcBootID) + len(dstBootID)
input := make([]byte, 0, inputLen)
input = append(input, globalKey...)
input = append(input, srcNodeIP...)
input = append(input, dstNodeIP...)
input = append(input, srcBootID...)
input = append(input, dstBootID...)
input = append(input, srcBootID[:36]...)
input = append(input, dstBootID[:36]...)
output := sha256.Sum256(input)
return output[:len(globalKey)]
}

// canonicalIP returns a canonical IPv4 address (4 bytes)
// in case we were dealing with a v4 mapped V6 address.
func canonicalIP(ip net.IP) net.IP {
if v4 := ip.To4(); v4 != nil {
return v4
}
return ip
}

// deriveNodeIPsecKey builds a per-node-pair ipSecKey object from the global
// ipSecKey object.
func deriveNodeIPsecKey(globalKey *ipSecKey, srcNodeIP, dstNodeIP net.IP, srcBootID, dstBootID string) *ipSecKey {
Expand All @@ -167,6 +179,9 @@ func deriveNodeIPsecKey(globalKey *ipSecKey, srcNodeIP, dstNodeIP net.IP, srcBoo
ESN: globalKey.ESN,
}

srcNodeIP = canonicalIP(srcNodeIP)
dstNodeIP = canonicalIP(dstNodeIP)

if globalKey.Aead != nil {
nodeKey.Aead = &netlink.XfrmStateAlgo{
Name: globalKey.Aead.Name,
Expand Down

0 comments on commit a652c12

Please sign in to comment.