mirror of
https://github.com/vishvananda/netlink
synced 2024-12-31 19:22:02 +00:00
Add support for Authenticated Encryption with Associated Data (AEAD) (#147)
Signed-off-by: Alessandro Boch <aboch@docker.com>
This commit is contained in:
parent
77483a0e69
commit
2b8dd8b419
@ -10,6 +10,7 @@ const (
|
||||
SizeofXfrmUsersaInfo = 0xe0
|
||||
SizeofXfrmAlgo = 0x44
|
||||
SizeofXfrmAlgoAuth = 0x48
|
||||
SizeofXfrmAlgoAEAD = 0x48
|
||||
SizeofXfrmEncapTmpl = 0x18
|
||||
SizeofXfrmUsersaFlush = 0x8
|
||||
)
|
||||
@ -194,6 +195,35 @@ func (msg *XfrmAlgoAuth) Serialize() []byte {
|
||||
// char alg_key[0];
|
||||
// }
|
||||
|
||||
type XfrmAlgoAEAD struct {
|
||||
AlgName [64]byte
|
||||
AlgKeyLen uint32
|
||||
AlgICVLen uint32
|
||||
AlgKey []byte
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgoAEAD) Len() int {
|
||||
return SizeofXfrmAlgoAEAD + int(msg.AlgKeyLen/8)
|
||||
}
|
||||
|
||||
func DeserializeXfrmAlgoAEAD(b []byte) *XfrmAlgoAEAD {
|
||||
ret := XfrmAlgoAEAD{}
|
||||
copy(ret.AlgName[:], b[0:64])
|
||||
ret.AlgKeyLen = *(*uint32)(unsafe.Pointer(&b[64]))
|
||||
ret.AlgICVLen = *(*uint32)(unsafe.Pointer(&b[68]))
|
||||
ret.AlgKey = b[72:ret.Len()]
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgoAEAD) Serialize() []byte {
|
||||
b := make([]byte, msg.Len())
|
||||
copy(b[0:64], msg.AlgName[:])
|
||||
copy(b[64:68], (*(*[4]byte)(unsafe.Pointer(&msg.AlgKeyLen)))[:])
|
||||
copy(b[68:72], (*(*[4]byte)(unsafe.Pointer(&msg.AlgICVLen)))[:])
|
||||
copy(b[72:msg.Len()], msg.AlgKey[:])
|
||||
return b
|
||||
}
|
||||
|
||||
// struct xfrm_encap_tmpl {
|
||||
// __u16 encap_type;
|
||||
// __be16 encap_sport;
|
||||
|
@ -239,3 +239,39 @@ func TestXfrmMarkDeserializeSerialize(t *testing.T) {
|
||||
msg := DeserializeXfrmMark(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgoAEAD) write(b []byte) {
|
||||
native := NativeEndian()
|
||||
copy(b[0:64], msg.AlgName[:])
|
||||
native.PutUint32(b[64:68], msg.AlgKeyLen)
|
||||
native.PutUint32(b[68:72], msg.AlgICVLen)
|
||||
copy(b[72:msg.Len()], msg.AlgKey[:])
|
||||
}
|
||||
|
||||
func (msg *XfrmAlgoAEAD) serializeSafe() []byte {
|
||||
b := make([]byte, msg.Len())
|
||||
msg.write(b)
|
||||
return b
|
||||
}
|
||||
|
||||
func deserializeXfrmAlgoAEADSafe(b []byte) *XfrmAlgoAEAD {
|
||||
var msg = XfrmAlgoAEAD{}
|
||||
copy(msg.AlgName[:], b[0:64])
|
||||
binary.Read(bytes.NewReader(b[64:68]), NativeEndian(), &msg.AlgKeyLen)
|
||||
binary.Read(bytes.NewReader(b[68:72]), NativeEndian(), &msg.AlgICVLen)
|
||||
msg.AlgKey = b[72:msg.Len()]
|
||||
return &msg
|
||||
}
|
||||
|
||||
func TestXfrmXfrmAlgoAeadDeserializeSerialize(t *testing.T) {
|
||||
native := NativeEndian()
|
||||
// use a 32 byte key len
|
||||
var orig = make([]byte, SizeofXfrmAlgoAEAD+36)
|
||||
rand.Read(orig)
|
||||
// set the key len to (256 + 32) bits
|
||||
var KeyLen uint32 = 0x00000120
|
||||
native.PutUint32(orig[64:68], KeyLen)
|
||||
safemsg := deserializeXfrmAlgoAEADSafe(orig)
|
||||
msg := DeserializeXfrmAlgoAEAD(orig)
|
||||
testDeserializeSerialize(t, orig, safemsg, msg)
|
||||
}
|
||||
|
@ -10,10 +10,18 @@ type XfrmStateAlgo struct {
|
||||
Name string
|
||||
Key []byte
|
||||
TruncateLen int // Auth only
|
||||
ICVLen int // AEAD only
|
||||
}
|
||||
|
||||
func (a XfrmStateAlgo) String() string {
|
||||
return fmt.Sprintf("{Name: %s, Key: 0x%x, TruncateLen: %d}", a.Name, a.Key, a.TruncateLen)
|
||||
base := fmt.Sprintf("{Name: %s, Key: 0x%x", a.Name, a.Key)
|
||||
if a.TruncateLen != 0 {
|
||||
base = fmt.Sprintf("%s, Truncate length: %d", base, a.TruncateLen)
|
||||
}
|
||||
if a.ICVLen != 0 {
|
||||
base = fmt.Sprintf("%s, ICV length: %d", base, a.ICVLen)
|
||||
}
|
||||
return fmt.Sprintf("%s}", base)
|
||||
}
|
||||
|
||||
// EncapType is an enum representing the optional packet encapsulation.
|
||||
@ -73,12 +81,13 @@ type XfrmState struct {
|
||||
Mark *XfrmMark
|
||||
Auth *XfrmStateAlgo
|
||||
Crypt *XfrmStateAlgo
|
||||
Aead *XfrmStateAlgo
|
||||
Encap *XfrmStateEncap
|
||||
}
|
||||
|
||||
func (sa XfrmState) String() string {
|
||||
return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Encap: %v",
|
||||
sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Encap)
|
||||
return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Aead: %v,Encap: %v",
|
||||
sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Aead, sa.Encap)
|
||||
}
|
||||
func (sa XfrmState) Print(stats bool) string {
|
||||
if !stats {
|
||||
|
@ -35,6 +35,20 @@ func writeStateAlgoAuth(a *XfrmStateAlgo) []byte {
|
||||
return algo.Serialize()
|
||||
}
|
||||
|
||||
func writeStateAlgoAead(a *XfrmStateAlgo) []byte {
|
||||
algo := nl.XfrmAlgoAEAD{
|
||||
AlgKeyLen: uint32(len(a.Key) * 8),
|
||||
AlgICVLen: uint32(a.ICVLen),
|
||||
AlgKey: a.Key,
|
||||
}
|
||||
end := len(a.Name)
|
||||
if end > 64 {
|
||||
end = 64
|
||||
}
|
||||
copy(algo.AlgName[:end], a.Name)
|
||||
return algo.Serialize()
|
||||
}
|
||||
|
||||
func writeMark(m *XfrmMark) []byte {
|
||||
mark := &nl.XfrmMark{
|
||||
Value: m.Value,
|
||||
@ -97,6 +111,10 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
|
||||
out := nl.NewRtAttr(nl.XFRMA_ALG_CRYPT, writeStateAlgo(state.Crypt))
|
||||
req.AddData(out)
|
||||
}
|
||||
if state.Aead != nil {
|
||||
out := nl.NewRtAttr(nl.XFRMA_ALG_AEAD, writeStateAlgoAead(state.Aead))
|
||||
req.AddData(out)
|
||||
}
|
||||
if state.Encap != nil {
|
||||
encapData := make([]byte, nl.SizeofXfrmEncapTmpl)
|
||||
encap := nl.DeserializeXfrmEncapTmpl(encapData)
|
||||
@ -271,6 +289,12 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) {
|
||||
state.Auth.Name = nl.BytesToString(algo.AlgName[:])
|
||||
state.Auth.Key = algo.AlgKey
|
||||
state.Auth.TruncateLen = int(algo.AlgTruncLen)
|
||||
case nl.XFRMA_ALG_AEAD:
|
||||
state.Aead = new(XfrmStateAlgo)
|
||||
algo := nl.DeserializeXfrmAlgoAEAD(attr.Value[:])
|
||||
state.Aead.Name = nl.BytesToString(algo.AlgName[:])
|
||||
state.Aead.Key = algo.AlgKey
|
||||
state.Aead.ICVLen = int(algo.AlgICVLen)
|
||||
case nl.XFRMA_ENCAP:
|
||||
encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:])
|
||||
state.Encap = new(XfrmStateEncap)
|
||||
|
@ -2,16 +2,20 @@ package netlink
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestXfrmStateAddGetDel(t *testing.T) {
|
||||
for _, s := range []*XfrmState{getBaseState(), getAeadState()} {
|
||||
testXfrmStateAddGetDel(t, s)
|
||||
}
|
||||
}
|
||||
|
||||
func testXfrmStateAddGetDel(t *testing.T, state *XfrmState) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
state := getBaseState()
|
||||
|
||||
if err := XfrmStateAdd(state); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -176,6 +180,23 @@ func getBaseState() *XfrmState {
|
||||
}
|
||||
}
|
||||
|
||||
func getAeadState() *XfrmState {
|
||||
// 128 key bits + 32 salt bits
|
||||
k, _ := hex.DecodeString("d0562776bf0e75830ba3f7f8eb6c09b555aa1177")
|
||||
return &XfrmState{
|
||||
Src: net.ParseIP("192.168.1.1"),
|
||||
Dst: net.ParseIP("192.168.2.2"),
|
||||
Proto: XFRM_PROTO_ESP,
|
||||
Mode: XFRM_MODE_TUNNEL,
|
||||
Spi: 2,
|
||||
Aead: &XfrmStateAlgo{
|
||||
Name: "rfc4106(gcm(aes))",
|
||||
Key: k,
|
||||
ICVLen: 64,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func compareStates(a, b *XfrmState) bool {
|
||||
if a == b {
|
||||
return true
|
||||
@ -185,9 +206,10 @@ func compareStates(a, b *XfrmState) bool {
|
||||
}
|
||||
return a.Src.Equal(b.Src) && a.Dst.Equal(b.Dst) &&
|
||||
a.Mode == b.Mode && a.Spi == b.Spi && a.Proto == b.Proto &&
|
||||
a.Auth.Name == b.Auth.Name && bytes.Equal(a.Auth.Key, b.Auth.Key) &&
|
||||
a.Crypt.Name == b.Crypt.Name && bytes.Equal(a.Crypt.Key, b.Crypt.Key) &&
|
||||
a.Mark.Value == b.Mark.Value && a.Mark.Mask == b.Mark.Mask
|
||||
compareAlgo(a.Auth, b.Auth) &&
|
||||
compareAlgo(a.Crypt, b.Crypt) &&
|
||||
compareAlgo(a.Aead, b.Aead) &&
|
||||
compareMarks(a.Mark, b.Mark)
|
||||
}
|
||||
|
||||
func compareLimits(a, b *XfrmState) bool {
|
||||
@ -200,3 +222,25 @@ func compareLimits(a, b *XfrmState) bool {
|
||||
a.Limits.TimeUseHard == b.Limits.TimeUseHard &&
|
||||
a.Limits.TimeUseSoft == b.Limits.TimeUseSoft
|
||||
}
|
||||
|
||||
func compareAlgo(a, b *XfrmStateAlgo) bool {
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
return a.Name == b.Name && bytes.Equal(a.Key, b.Key) &&
|
||||
(a.TruncateLen == 0 || a.TruncateLen == b.TruncateLen) &&
|
||||
(a.ICVLen == 0 || a.ICVLen == b.ICVLen)
|
||||
}
|
||||
|
||||
func compareMarks(a, b *XfrmMark) bool {
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
return a.Value == b.Value && a.Mask == b.Mask
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user