From e0c7f7282294302b31899a7d370b3d07731dc476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Thu, 5 May 2022 13:17:30 +0200 Subject: [PATCH 01/11] update spao extension header --- pkg/slayers/extn.go | 74 ++++++++++++++++++++++++++++------------ pkg/slayers/extn_test.go | 49 +++++++++++++++++--------- 2 files changed, 85 insertions(+), 38 deletions(-) diff --git a/pkg/slayers/extn.go b/pkg/slayers/extn.go index 94996ed80a..9672eae480 100644 --- a/pkg/slayers/extn.go +++ b/pkg/slayers/extn.go @@ -15,6 +15,7 @@ package slayers import ( + "encoding/binary" "fmt" "github.com/google/gopacket" @@ -451,7 +452,8 @@ func (e *EndToEndExtnSkipper) NextLayerType() gopacket.LayerType { type PacketAuthAlg uint8 const ( - PacketAuthCMAC PacketAuthAlg = 0 + PacketAuthCMAC PacketAuthAlg = iota + PacketAuthSHA1_AES_CBC ) // PacketAuthenticatorOption wraps an EndToEndOption of OptTypeAuthenticator. @@ -462,16 +464,17 @@ type PacketAuthenticatorOption struct { } // NewPacketAuthenticatorOption creates a new EndToEndOption of -// OptTypeAuthenticator, initialized with the given algorithm type and -// authenticator data. -func NewPacketAuthenticatorOption(alg PacketAuthAlg, data []byte) PacketAuthenticatorOption { +// OptTypeAuthenticator, initialized with the given SPAO data. +func NewPacketAuthenticatorOption(spi uint32, alg PacketAuthAlg, ts uint32, + sn uint32, auth []byte) PacketAuthenticatorOption { o := PacketAuthenticatorOption{EndToEndOption: new(EndToEndOption)} - o.Reset(alg, data) + o.Reset(spi, alg, ts, sn, auth) return o } // ParsePacketAuthenticatorOption parses o as a packet authenticator option. -// Performs minimal checks to ensure that Algorithm and Authenticator are set. +// Performs minimal checks to ensure that SPI, Algorithm, timestamp, RSV, and +// sequence number are set. // Checking the size and content of the Authenticator data must be done by the // caller. func ParsePacketAuthenticatorOption(o *EndToEndOption) (PacketAuthenticatorOption, error) { @@ -479,42 +482,71 @@ func ParsePacketAuthenticatorOption(o *EndToEndOption) (PacketAuthenticatorOptio return PacketAuthenticatorOption{}, serrors.New("wrong option type", "expected", OptTypeAuthenticator, "actual", o.OptType) } - if len(o.OptData) < 2 { + if len(o.OptData) < 12 { return PacketAuthenticatorOption{}, - serrors.New("buffer too short", "expected", 2, "actual", len(o.OptData)) + serrors.New("buffer too short", "expected", 12, "actual", len(o.OptData)) } return PacketAuthenticatorOption{o}, nil } -// Reset reinitializes the underlying EndToEndOption with the given algorithm -// type and authenticator data. +// Reset reinitializes the underlying EndToEndOption with the SPAO data. // Reuses the OptData buffer if it is of sufficient capacity. -func (o PacketAuthenticatorOption) Reset(alg PacketAuthAlg, data []byte) { +func (o PacketAuthenticatorOption) Reset(spi uint32, alg PacketAuthAlg, + ts uint32, sn uint32, auth []byte) { o.OptType = OptTypeAuthenticator - n := 1 + len(data) + n := 12 + len(auth) // 4 + 1 + 3 + 1 + 3 + len(data) if n <= cap(o.OptData) { o.OptData = o.OptData[:n] } else { o.OptData = make([]byte, n) } - o.OptData[0] = byte(alg) - copy(o.OptData[1:], data) - - o.OptAlign = [2]uint8{4, 1} + binary.BigEndian.PutUint32(o.OptData[:4], spi) + o.OptData[4] = byte(alg) + o.OptData[5] = byte(ts >> 16) + o.OptData[6] = byte(ts >> 8) + o.OptData[7] = byte(ts) + o.OptData[8] = byte(0) + o.OptData[9] = byte(sn >> 16) + o.OptData[10] = byte(sn >> 8) + o.OptData[11] = byte(sn) + copy(o.OptData[12:], auth) + + o.OptAlign = [2]uint8{4, 2} // reset unused/implicit fields o.OptDataLen = 0 o.ActualLength = 0 } +// SPI returns a slice of the underlying SPI buffer. +// Changes to this slice will be reflected on the wire when +// the extension is serialized. +func (o PacketAuthenticatorOption) SPI() uint32 { + return binary.BigEndian.Uint32(o.OptData[:4]) +} + // Algorithm returns the algorithm type stored in the data buffer. func (o PacketAuthenticatorOption) Algorithm() PacketAuthAlg { - return PacketAuthAlg(o.OptData[0]) + return PacketAuthAlg(o.OptData[4]) +} + +// Timestamp returns a slice of the underlying timestamp buffer. +// Changes to this slice will be reflected on the wire when +// the extension is serialized. +func (o PacketAuthenticatorOption) Timestamp() uint32 { + return uint32(o.OptData[5])<<16 + uint32(o.OptData[6])<<8 + uint32(o.OptData[7]) +} + +// SequenceNumber returns a slice of the underlying sequence number buffer. +// Changes to this slice will be reflected on the wire when +// the extension is serialized. +func (o PacketAuthenticatorOption) SequenceNumber() uint32 { + return uint32(o.OptData[9])<<16 + uint32(o.OptData[10])<<8 + uint32(o.OptData[11]) } -// Algorithm returns the authenticator data part of the data buffer. -// Returns a slice of the underlying OptData buffer. Changes to this slice will -// be reflected on the wire when the extension is serialized. +// Authenticator returns slice of the underlying auth buffer. +// Changes to this slice will be reflected on the wire when +// the extension is serialized. func (o PacketAuthenticatorOption) Authenticator() []byte { - return o.OptData[1:] + return o.OptData[12:] } diff --git a/pkg/slayers/extn_test.go b/pkg/slayers/extn_test.go index 6f89017248..6fc831b756 100644 --- a/pkg/slayers/extn_test.go +++ b/pkg/slayers/extn_test.go @@ -15,6 +15,7 @@ package slayers_test import ( + "encoding/binary" "fmt" "testing" @@ -542,31 +543,42 @@ func prepRawPacketWithExtn(t *testing.T, extns ...slayers.L4ProtocolType) []byte return buf.Bytes() } +var spi = binary.LittleEndian.Uint32([]byte{1, 0, 0, 0}) +var algo = slayers.PacketAuthSHA1_AES_CBC +var ts = binary.LittleEndian.Uint32([]byte{1, 2, 3, 0}) +var sn = binary.LittleEndian.Uint32([]byte{4, 5, 6, 0}) var optAuthMAC = []byte("16byte_mac_foooo") -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// |Next Header=UDP| Hdr Ext Len=5 | PadN Option=1 |Opt Data Len=1 | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | 0 | Auth Option=2 |Opt Data Len=17| Algo = CMAC | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | | -// + + -// | | -// + 16-octet MAC data + -// | | -// + + -// | | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | NextHdr=UDP | ExtLen | OptType=2 | OptDataLen | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Security Parameter Index | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Algorithm | Timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | RSV | Sequence Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// + + +// | | +// + 16-octet MAC data + +// | | +// + + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + var rawE2EOptAuth = append( []byte{ - 0x11, 0x05, 0x01, 0x01, - 0x0, 0x2, 0x11, 0x0, + 0x11, 0x7, 0x2, 0x1c, + 0x0, 0x0, 0x0, 0x1, + 0x1, 0x3, 0x2, 0x1, + 0x0, 0x6, 0x5, 0x4, }, optAuthMAC..., ) func TestOptAuthenticatorSerialize(t *testing.T) { - optAuth := slayers.NewPacketAuthenticatorOption(slayers.PacketAuthCMAC, optAuthMAC) + optAuth := slayers.NewPacketAuthenticatorOption(spi, algo, ts, sn, optAuthMAC) e2e := slayers.EndToEndExtn{} e2e.NextHdr = slayers.L4UDP @@ -591,7 +603,10 @@ func TestOptAuthenticatorDeserialize(t *testing.T) { require.NoError(t, err, "FindOption") auth, err := slayers.ParsePacketAuthenticatorOption(optAuth) require.NoError(t, err, "ParsePacketAuthenticatorOption") - assert.Equal(t, slayers.PacketAuthCMAC, auth.Algorithm(), "Algorithm Type") + assert.Equal(t, spi, auth.SPI(), "SPI") + assert.Equal(t, algo, auth.Algorithm(), "Algorithm Type") + assert.Equal(t, ts, auth.Timestamp(), "Timestamp") + assert.Equal(t, sn, auth.SequenceNumber(), "Sequence Number") assert.Equal(t, optAuthMAC, auth.Authenticator(), "Authenticator data (MAC)") } From 9bad2c8a84b89fe01cf0f2ed7fb76bef08adfd37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Thu, 12 May 2022 15:00:10 +0200 Subject: [PATCH 02/11] r1 --- pkg/slayers/extn.go | 110 +++++++++++++++++++++++++++++++++------ pkg/slayers/extn_test.go | 68 +++++++++++++++++++++--- 2 files changed, 153 insertions(+), 25 deletions(-) diff --git a/pkg/slayers/extn.go b/pkg/slayers/extn.go index 9672eae480..c8e50d3943 100644 --- a/pkg/slayers/extn.go +++ b/pkg/slayers/extn.go @@ -447,6 +447,78 @@ func (e *EndToEndExtnSkipper) NextLayerType() gopacket.LayerType { return scionNextLayerTypeAfterE2E(e.NextHdr) } +// PacketAuthSPI is the identifier for the key used for the +// packet authentication option. It ranges [1, 2^21-1] +type PacketAuthSPI uint32 + +type DRKeyType uint8 + +const ( + ASHost DRKeyType = iota + HostHost +) + +type DRKeyDirection uint8 + +const ( + SenderSide DRKeyDirection = iota + ReceiverSide +) + +type DRKeyEpochType uint8 + +const ( + Later DRKeyEpochType = iota + Earlier +) + +func (p PacketAuthSPI) Type() DRKeyType { + if p^(1<<13) == 0 { + return ASHost + } + return HostHost +} + +func (p PacketAuthSPI) Direction() DRKeyDirection { + if p^(1<<14) == 0 { + return SenderSide + } + return ReceiverSide +} + +func (p PacketAuthSPI) Epoch() DRKeyEpochType { + if p^(1<<14) == 0 { + return Later + } + return Earlier +} + +func (p PacketAuthSPI) DRKeyProto() uint16 { + return uint16(p >> 16) +} + +func MakePacketAuthSPIDrkey(proto uint16, drkeyType DRKeyType, + dir DRKeyDirection, epoch DRKeyEpochType) (PacketAuthSPI, error) { + if proto < 1 { + return 0, serrors.New("Invalid proto identifier value") + } + if drkeyType > 1 { + return 0, serrors.New("Invalid DRKeyType value") + } + if dir > 1 { + return 0, serrors.New("Invalid DRKeyDirection value") + } + if epoch > 1 { + return 0, serrors.New("Invalid DRKeyEpochType value") + } + spi := uint32((drkeyType & 0x1)) << 13 + spi |= uint32((dir & 0x1)) << 14 + spi |= uint32((epoch & 0x1)) << 15 + spi |= uint32(proto) << 16 + + return PacketAuthSPI(spi), nil +} + // PacketAuthAlg is the enumerator for authenticator algorithm types in the // packet authenticator option. type PacketAuthAlg uint8 @@ -465,15 +537,15 @@ type PacketAuthenticatorOption struct { // NewPacketAuthenticatorOption creates a new EndToEndOption of // OptTypeAuthenticator, initialized with the given SPAO data. -func NewPacketAuthenticatorOption(spi uint32, alg PacketAuthAlg, ts uint32, - sn uint32, auth []byte) PacketAuthenticatorOption { +func NewPacketAuthenticatorOption(spi PacketAuthSPI, alg PacketAuthAlg, ts uint32, + sn uint32, auth []byte) (PacketAuthenticatorOption, error) { o := PacketAuthenticatorOption{EndToEndOption: new(EndToEndOption)} - o.Reset(spi, alg, ts, sn, auth) - return o + err := o.Reset(spi, alg, ts, sn, auth) + return o, err } // ParsePacketAuthenticatorOption parses o as a packet authenticator option. -// Performs minimal checks to ensure that SPI, Algorithm, timestamp, RSV, and +// Performs minimal checks to ensure that SPI, algorithm, timestamp, RSV, and // sequence number are set. // Checking the size and content of the Authenticator data must be done by the // caller. @@ -491,8 +563,16 @@ func ParsePacketAuthenticatorOption(o *EndToEndOption) (PacketAuthenticatorOptio // Reset reinitializes the underlying EndToEndOption with the SPAO data. // Reuses the OptData buffer if it is of sufficient capacity. -func (o PacketAuthenticatorOption) Reset(spi uint32, alg PacketAuthAlg, - ts uint32, sn uint32, auth []byte) { +func (o PacketAuthenticatorOption) Reset(spi PacketAuthSPI, alg PacketAuthAlg, + ts uint32, sn uint32, auth []byte) error { + + if ts > (1 << 24) { + return serrors.New("Timestamp value should be smaller than 2^24", "ts", ts) + } + if sn > (1 << 24) { + return serrors.New("Sequence number should be smaller than 2^24", "sn", sn) + } + o.OptType = OptTypeAuthenticator n := 12 + len(auth) // 4 + 1 + 3 + 1 + 3 + len(data) @@ -501,7 +581,7 @@ func (o PacketAuthenticatorOption) Reset(spi uint32, alg PacketAuthAlg, } else { o.OptData = make([]byte, n) } - binary.BigEndian.PutUint32(o.OptData[:4], spi) + binary.BigEndian.PutUint32(o.OptData[:4], uint32(spi)) o.OptData[4] = byte(alg) o.OptData[5] = byte(ts >> 16) o.OptData[6] = byte(ts >> 8) @@ -516,11 +596,11 @@ func (o PacketAuthenticatorOption) Reset(spi uint32, alg PacketAuthAlg, // reset unused/implicit fields o.OptDataLen = 0 o.ActualLength = 0 + + return nil } -// SPI returns a slice of the underlying SPI buffer. -// Changes to this slice will be reflected on the wire when -// the extension is serialized. +// SPI returns returns the value set in the homonym field in the extension. func (o PacketAuthenticatorOption) SPI() uint32 { return binary.BigEndian.Uint32(o.OptData[:4]) } @@ -530,16 +610,12 @@ func (o PacketAuthenticatorOption) Algorithm() PacketAuthAlg { return PacketAuthAlg(o.OptData[4]) } -// Timestamp returns a slice of the underlying timestamp buffer. -// Changes to this slice will be reflected on the wire when -// the extension is serialized. +// Timestamp returns the value set in the homonym field in the extension. func (o PacketAuthenticatorOption) Timestamp() uint32 { return uint32(o.OptData[5])<<16 + uint32(o.OptData[6])<<8 + uint32(o.OptData[7]) } -// SequenceNumber returns a slice of the underlying sequence number buffer. -// Changes to this slice will be reflected on the wire when -// the extension is serialized. +// SequenceNumber returns the value set in the homonym field in the extension. func (o PacketAuthenticatorOption) SequenceNumber() uint32 { return uint32(o.OptData[9])<<16 + uint32(o.OptData[10])<<8 + uint32(o.OptData[11]) } diff --git a/pkg/slayers/extn_test.go b/pkg/slayers/extn_test.go index 6fc831b756..3eb072c895 100644 --- a/pkg/slayers/extn_test.go +++ b/pkg/slayers/extn_test.go @@ -578,17 +578,63 @@ var rawE2EOptAuth = append( ) func TestOptAuthenticatorSerialize(t *testing.T) { - optAuth := slayers.NewPacketAuthenticatorOption(spi, algo, ts, sn, optAuthMAC) + cases := []struct { + name string + spi slayers.PacketAuthSPI + algo slayers.PacketAuthAlg + ts uint32 + sn uint32 + optAuth []byte + err assert.ErrorAssertionFunc + }{ + { + name: "correct", + spi: slayers.PacketAuthSPI(spi), + algo: slayers.PacketAuthAlg(algo), + ts: ts, + sn: sn, + optAuth: optAuthMAC, + err: assert.NoError, + }, + { + name: "bad_ts", + spi: slayers.PacketAuthSPI(spi), + algo: slayers.PacketAuthAlg(algo), + ts: binary.LittleEndian.Uint32([]byte{1, 2, 3, 1}), + sn: sn, + optAuth: optAuthMAC, + err: assert.Error, + }, + { + name: "bad_sn", + spi: slayers.PacketAuthSPI(spi), + algo: slayers.PacketAuthAlg(algo), + ts: ts, + sn: binary.LittleEndian.Uint32([]byte{4, 5, 6, 1}), + optAuth: optAuthMAC, + err: assert.Error, + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + spao, err := slayers.NewPacketAuthenticatorOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) + c.err(t, err, "NewPacketAuthenticatorOption") - e2e := slayers.EndToEndExtn{} - e2e.NextHdr = slayers.L4UDP - e2e.Options = []*slayers.EndToEndOption{optAuth.EndToEndOption} + if err != nil { + return + } - b := gopacket.NewSerializeBuffer() - opts := gopacket.SerializeOptions{FixLengths: true} - assert.NoError(t, e2e.SerializeTo(b, opts), "SerializeTo") + e2e := slayers.EndToEndExtn{} + e2e.NextHdr = slayers.L4UDP + e2e.Options = []*slayers.EndToEndOption{spao.EndToEndOption} - assert.Equal(t, rawE2EOptAuth, b.Bytes(), "Raw Buffer") + b := gopacket.NewSerializeBuffer() + opts := gopacket.SerializeOptions{FixLengths: true} + assert.NoError(t, e2e.SerializeTo(b, opts), "SerializeTo") + + assert.Equal(t, rawE2EOptAuth, b.Bytes(), "Raw Buffer") + }) + } } func TestOptAuthenticatorDeserialize(t *testing.T) { @@ -610,6 +656,12 @@ func TestOptAuthenticatorDeserialize(t *testing.T) { assert.Equal(t, optAuthMAC, auth.Authenticator(), "Authenticator data (MAC)") } +func TestMakePacketAuthSPIDrkey(t *testing.T) { + spi, err := slayers.MakePacketAuthSPIDrkey(1, slayers.ASHost, slayers.SenderSide, slayers.Later) + require.NoError(t, err) + assert.EqualValues(t, binary.LittleEndian.Uint32([]byte{0, 0, 1, 0}), spi) +} + func TestOptAuthenticatorDeserializeCorrupt(t *testing.T) { optAuthCorrupt := slayers.EndToEndOption{ OptType: slayers.OptTypeAuthenticator, From 30443e54f14bb79fb467a832de0217e16e08af4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Thu, 12 May 2022 15:47:55 +0200 Subject: [PATCH 03/11] r2 --- pkg/slayers/extn.go | 18 ++++++++---------- pkg/slayers/extn_test.go | 30 +++++++++++++++++------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/pkg/slayers/extn.go b/pkg/slayers/extn.go index c8e50d3943..4a38c8f036 100644 --- a/pkg/slayers/extn.go +++ b/pkg/slayers/extn.go @@ -538,10 +538,10 @@ type PacketAuthenticatorOption struct { // NewPacketAuthenticatorOption creates a new EndToEndOption of // OptTypeAuthenticator, initialized with the given SPAO data. func NewPacketAuthenticatorOption(spi PacketAuthSPI, alg PacketAuthAlg, ts uint32, - sn uint32, auth []byte) (PacketAuthenticatorOption, error) { + sn uint32, auth []byte) PacketAuthenticatorOption { o := PacketAuthenticatorOption{EndToEndOption: new(EndToEndOption)} - err := o.Reset(spi, alg, ts, sn, auth) - return o, err + o.Reset(spi, alg, ts, sn, auth) + return o } // ParsePacketAuthenticatorOption parses o as a packet authenticator option. @@ -564,13 +564,13 @@ func ParsePacketAuthenticatorOption(o *EndToEndOption) (PacketAuthenticatorOptio // Reset reinitializes the underlying EndToEndOption with the SPAO data. // Reuses the OptData buffer if it is of sufficient capacity. func (o PacketAuthenticatorOption) Reset(spi PacketAuthSPI, alg PacketAuthAlg, - ts uint32, sn uint32, auth []byte) error { + ts uint32, sn uint32, auth []byte) { - if ts > (1 << 24) { - return serrors.New("Timestamp value should be smaller than 2^24", "ts", ts) + if ts >= (1 << 24) { + panic("Timestamp value should be smaller than 2^24") } - if sn > (1 << 24) { - return serrors.New("Sequence number should be smaller than 2^24", "sn", sn) + if sn >= (1 << 24) { + panic("Sequence number should be smaller than 2^24") } o.OptType = OptTypeAuthenticator @@ -596,8 +596,6 @@ func (o PacketAuthenticatorOption) Reset(spi PacketAuthSPI, alg PacketAuthAlg, // reset unused/implicit fields o.OptDataLen = 0 o.ActualLength = 0 - - return nil } // SPI returns returns the value set in the homonym field in the extension. diff --git a/pkg/slayers/extn_test.go b/pkg/slayers/extn_test.go index 3eb072c895..475d4ab34b 100644 --- a/pkg/slayers/extn_test.go +++ b/pkg/slayers/extn_test.go @@ -585,45 +585,49 @@ func TestOptAuthenticatorSerialize(t *testing.T) { ts uint32 sn uint32 optAuth []byte - err assert.ErrorAssertionFunc + panics bool }{ { name: "correct", spi: slayers.PacketAuthSPI(spi), - algo: slayers.PacketAuthAlg(algo), + algo: algo, ts: ts, sn: sn, optAuth: optAuthMAC, - err: assert.NoError, + panics: false, }, { name: "bad_ts", spi: slayers.PacketAuthSPI(spi), - algo: slayers.PacketAuthAlg(algo), - ts: binary.LittleEndian.Uint32([]byte{1, 2, 3, 1}), + algo: algo, + ts: binary.LittleEndian.Uint32([]byte{0, 0, 0, 1}), sn: sn, optAuth: optAuthMAC, - err: assert.Error, + panics: true, }, { name: "bad_sn", spi: slayers.PacketAuthSPI(spi), - algo: slayers.PacketAuthAlg(algo), + algo: algo, ts: ts, - sn: binary.LittleEndian.Uint32([]byte{4, 5, 6, 1}), + sn: binary.LittleEndian.Uint32([]byte{0, 0, 0, 1}), optAuth: optAuthMAC, - err: assert.Error, + panics: true, }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { - spao, err := slayers.NewPacketAuthenticatorOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) - c.err(t, err, "NewPacketAuthenticatorOption") - - if err != nil { + if c.panics { + assert.Panics(t, func() { + slayers.NewPacketAuthenticatorOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) + }, + "The code did not panic", + ) return } + spao := slayers.NewPacketAuthenticatorOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) + e2e := slayers.EndToEndExtn{} e2e.NextHdr = slayers.L4UDP e2e.Options = []*slayers.EndToEndOption{spao.EndToEndOption} From d488630aaddf1effc5b395d556f6dbc0cca27468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Fri, 27 May 2022 12:37:42 +0200 Subject: [PATCH 04/11] r3 --- pkg/slayers/extn.go | 11 ++++++++--- pkg/slayers/extn_test.go | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/slayers/extn.go b/pkg/slayers/extn.go index 4a38c8f036..7db22056fd 100644 --- a/pkg/slayers/extn.go +++ b/pkg/slayers/extn.go @@ -448,7 +448,8 @@ func (e *EndToEndExtnSkipper) NextLayerType() gopacket.LayerType { } // PacketAuthSPI is the identifier for the key used for the -// packet authentication option. It ranges [1, 2^21-1] +// packet authentication option. DRKey values are in the +// range [1, 2^21-1]. type PacketAuthSPI uint32 type DRKeyType uint8 @@ -497,6 +498,10 @@ func (p PacketAuthSPI) DRKeyProto() uint16 { return uint16(p >> 16) } +func (p PacketAuthSPI) IsDRKey() bool { + return p > 0 && p < (1<<21) +} + func MakePacketAuthSPIDrkey(proto uint16, drkeyType DRKeyType, dir DRKeyDirection, epoch DRKeyEpochType) (PacketAuthSPI, error) { if proto < 1 { @@ -599,8 +604,8 @@ func (o PacketAuthenticatorOption) Reset(spi PacketAuthSPI, alg PacketAuthAlg, } // SPI returns returns the value set in the homonym field in the extension. -func (o PacketAuthenticatorOption) SPI() uint32 { - return binary.BigEndian.Uint32(o.OptData[:4]) +func (o PacketAuthenticatorOption) SPI() PacketAuthSPI { + return PacketAuthSPI(binary.BigEndian.Uint32(o.OptData[:4])) } // Algorithm returns the algorithm type stored in the data buffer. diff --git a/pkg/slayers/extn_test.go b/pkg/slayers/extn_test.go index 475d4ab34b..7c66d91e35 100644 --- a/pkg/slayers/extn_test.go +++ b/pkg/slayers/extn_test.go @@ -543,7 +543,7 @@ func prepRawPacketWithExtn(t *testing.T, extns ...slayers.L4ProtocolType) []byte return buf.Bytes() } -var spi = binary.LittleEndian.Uint32([]byte{1, 0, 0, 0}) +var spi = slayers.PacketAuthSPI(binary.LittleEndian.Uint32([]byte{1, 0, 0, 0})) var algo = slayers.PacketAuthSHA1_AES_CBC var ts = binary.LittleEndian.Uint32([]byte{1, 2, 3, 0}) var sn = binary.LittleEndian.Uint32([]byte{4, 5, 6, 0}) From fadf34fd40934af6af6d5db137981c3bc53ccf5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Mon, 18 Jul 2022 12:14:43 +0200 Subject: [PATCH 05/11] lint --- pkg/slayers/extn_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/slayers/extn_test.go b/pkg/slayers/extn_test.go index 7c66d91e35..68b4f08580 100644 --- a/pkg/slayers/extn_test.go +++ b/pkg/slayers/extn_test.go @@ -589,7 +589,7 @@ func TestOptAuthenticatorSerialize(t *testing.T) { }{ { name: "correct", - spi: slayers.PacketAuthSPI(spi), + spi: spi, algo: algo, ts: ts, sn: sn, @@ -598,7 +598,7 @@ func TestOptAuthenticatorSerialize(t *testing.T) { }, { name: "bad_ts", - spi: slayers.PacketAuthSPI(spi), + spi: spi, algo: algo, ts: binary.LittleEndian.Uint32([]byte{0, 0, 0, 1}), sn: sn, @@ -607,7 +607,7 @@ func TestOptAuthenticatorSerialize(t *testing.T) { }, { name: "bad_sn", - spi: slayers.PacketAuthSPI(spi), + spi: spi, algo: algo, ts: ts, sn: binary.LittleEndian.Uint32([]byte{0, 0, 0, 1}), From 940978d2ea6899d10cd1d237be2d28f7f8af6bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Mon, 18 Jul 2022 17:52:51 +0200 Subject: [PATCH 06/11] r4 --- pkg/slayers/extn.go | 74 ++++++++++++++++++++++++---------------- pkg/slayers/extn_test.go | 9 +++-- 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/pkg/slayers/extn.go b/pkg/slayers/extn.go index 7db22056fd..0568b548f5 100644 --- a/pkg/slayers/extn.go +++ b/pkg/slayers/extn.go @@ -450,78 +450,83 @@ func (e *EndToEndExtnSkipper) NextLayerType() gopacket.LayerType { // PacketAuthSPI is the identifier for the key used for the // packet authentication option. DRKey values are in the // range [1, 2^21-1]. -type PacketAuthSPI uint32 +type PacketAuthenticatorSPI uint32 -type DRKeyType uint8 +type PacketAuthenticatorDRKeyType uint8 const ( - ASHost DRKeyType = iota + ASHost PacketAuthenticatorDRKeyType = iota HostHost ) -type DRKeyDirection uint8 +type PacketAuthenticatorDRKeyDirection uint8 const ( - SenderSide DRKeyDirection = iota + SenderSide PacketAuthenticatorDRKeyDirection = iota ReceiverSide ) -type DRKeyEpochType uint8 +type PacketAuthenticatorDRKeyEpochType uint8 const ( - Later DRKeyEpochType = iota + Later PacketAuthenticatorDRKeyEpochType = iota Earlier ) -func (p PacketAuthSPI) Type() DRKeyType { - if p^(1<<13) == 0 { +func (p PacketAuthenticatorSPI) Type() PacketAuthenticatorDRKeyType { + if p&(1<<13) == 0 { return ASHost } return HostHost } -func (p PacketAuthSPI) Direction() DRKeyDirection { - if p^(1<<14) == 0 { +func (p PacketAuthenticatorSPI) Direction() PacketAuthenticatorDRKeyDirection { + if p&(1<<14) == 0 { return SenderSide } return ReceiverSide } -func (p PacketAuthSPI) Epoch() DRKeyEpochType { - if p^(1<<14) == 0 { +func (p PacketAuthenticatorSPI) Epoch() PacketAuthenticatorDRKeyEpochType { + if p&(1<<15) == 0 { return Later } return Earlier } -func (p PacketAuthSPI) DRKeyProto() uint16 { +func (p PacketAuthenticatorSPI) DRKeyProto() uint16 { return uint16(p >> 16) } -func (p PacketAuthSPI) IsDRKey() bool { +func (p PacketAuthenticatorSPI) IsDRKey() bool { return p > 0 && p < (1<<21) } -func MakePacketAuthSPIDrkey(proto uint16, drkeyType DRKeyType, - dir DRKeyDirection, epoch DRKeyEpochType) (PacketAuthSPI, error) { +func MakePacketAuthSPIDrkey( + proto uint16, + drkeyType PacketAuthenticatorDRKeyType, + dir PacketAuthenticatorDRKeyDirection, + epoch PacketAuthenticatorDRKeyEpochType, +) PacketAuthenticatorSPI { + if proto < 1 { - return 0, serrors.New("Invalid proto identifier value") + panic("Invalid proto identifier value") } if drkeyType > 1 { - return 0, serrors.New("Invalid DRKeyType value") + panic("Invalid DRKeyType value") } if dir > 1 { - return 0, serrors.New("Invalid DRKeyDirection value") + panic("Invalid DRKeyDirection value") } if epoch > 1 { - return 0, serrors.New("Invalid DRKeyEpochType value") + panic("Invalid DRKeyEpochType value") } spi := uint32((drkeyType & 0x1)) << 13 spi |= uint32((dir & 0x1)) << 14 spi |= uint32((epoch & 0x1)) << 15 spi |= uint32(proto) << 16 - return PacketAuthSPI(spi), nil + return PacketAuthenticatorSPI(spi) } // PacketAuthAlg is the enumerator for authenticator algorithm types in the @@ -542,8 +547,14 @@ type PacketAuthenticatorOption struct { // NewPacketAuthenticatorOption creates a new EndToEndOption of // OptTypeAuthenticator, initialized with the given SPAO data. -func NewPacketAuthenticatorOption(spi PacketAuthSPI, alg PacketAuthAlg, ts uint32, - sn uint32, auth []byte) PacketAuthenticatorOption { +func NewPacketAuthenticatorOption( + spi PacketAuthenticatorSPI, + alg PacketAuthAlg, + ts uint32, + sn uint32, + auth []byte, +) PacketAuthenticatorOption { + o := PacketAuthenticatorOption{EndToEndOption: new(EndToEndOption)} o.Reset(spi, alg, ts, sn, auth) return o @@ -568,8 +579,13 @@ func ParsePacketAuthenticatorOption(o *EndToEndOption) (PacketAuthenticatorOptio // Reset reinitializes the underlying EndToEndOption with the SPAO data. // Reuses the OptData buffer if it is of sufficient capacity. -func (o PacketAuthenticatorOption) Reset(spi PacketAuthSPI, alg PacketAuthAlg, - ts uint32, sn uint32, auth []byte) { +func (o PacketAuthenticatorOption) Reset( + spi PacketAuthenticatorSPI, + alg PacketAuthAlg, + ts uint32, + sn uint32, + auth []byte, +) { if ts >= (1 << 24) { panic("Timestamp value should be smaller than 2^24") @@ -586,7 +602,7 @@ func (o PacketAuthenticatorOption) Reset(spi PacketAuthSPI, alg PacketAuthAlg, } else { o.OptData = make([]byte, n) } - binary.BigEndian.PutUint32(o.OptData[:4], uint32(spi)) + binary.LittleEndian.PutUint32(o.OptData[:4], uint32(spi)) o.OptData[4] = byte(alg) o.OptData[5] = byte(ts >> 16) o.OptData[6] = byte(ts >> 8) @@ -604,8 +620,8 @@ func (o PacketAuthenticatorOption) Reset(spi PacketAuthSPI, alg PacketAuthAlg, } // SPI returns returns the value set in the homonym field in the extension. -func (o PacketAuthenticatorOption) SPI() PacketAuthSPI { - return PacketAuthSPI(binary.BigEndian.Uint32(o.OptData[:4])) +func (o PacketAuthenticatorOption) SPI() PacketAuthenticatorSPI { + return PacketAuthenticatorSPI(binary.LittleEndian.Uint32(o.OptData[:4])) } // Algorithm returns the algorithm type stored in the data buffer. diff --git a/pkg/slayers/extn_test.go b/pkg/slayers/extn_test.go index 68b4f08580..a262cdee26 100644 --- a/pkg/slayers/extn_test.go +++ b/pkg/slayers/extn_test.go @@ -543,7 +543,7 @@ func prepRawPacketWithExtn(t *testing.T, extns ...slayers.L4ProtocolType) []byte return buf.Bytes() } -var spi = slayers.PacketAuthSPI(binary.LittleEndian.Uint32([]byte{1, 0, 0, 0})) +var spi = slayers.PacketAuthenticatorSPI(binary.LittleEndian.Uint32([]byte{0, 0x80, 1, 0})) var algo = slayers.PacketAuthSHA1_AES_CBC var ts = binary.LittleEndian.Uint32([]byte{1, 2, 3, 0}) var sn = binary.LittleEndian.Uint32([]byte{4, 5, 6, 0}) @@ -570,7 +570,7 @@ var optAuthMAC = []byte("16byte_mac_foooo") var rawE2EOptAuth = append( []byte{ 0x11, 0x7, 0x2, 0x1c, - 0x0, 0x0, 0x0, 0x1, + 0x0, 0x80, 0x1, 0x0, 0x1, 0x3, 0x2, 0x1, 0x0, 0x6, 0x5, 0x4, }, @@ -580,7 +580,7 @@ var rawE2EOptAuth = append( func TestOptAuthenticatorSerialize(t *testing.T) { cases := []struct { name string - spi slayers.PacketAuthSPI + spi slayers.PacketAuthenticatorSPI algo slayers.PacketAuthAlg ts uint32 sn uint32 @@ -661,8 +661,7 @@ func TestOptAuthenticatorDeserialize(t *testing.T) { } func TestMakePacketAuthSPIDrkey(t *testing.T) { - spi, err := slayers.MakePacketAuthSPIDrkey(1, slayers.ASHost, slayers.SenderSide, slayers.Later) - require.NoError(t, err) + spi := slayers.MakePacketAuthSPIDrkey(1, slayers.ASHost, slayers.SenderSide, slayers.Later) assert.EqualValues(t, binary.LittleEndian.Uint32([]byte{0, 0, 1, 0}), spi) } From 05f4c9a26e474343fd71a0b32cccfb362fcb0729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Tue, 19 Jul 2022 15:02:06 +0200 Subject: [PATCH 07/11] r5 --- pkg/slayers/extn.go | 20 ++++++++++---------- pkg/slayers/extn_test.go | 15 +++++++++++---- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/pkg/slayers/extn.go b/pkg/slayers/extn.go index 0568b548f5..56021e34c4 100644 --- a/pkg/slayers/extn.go +++ b/pkg/slayers/extn.go @@ -474,28 +474,28 @@ const ( ) func (p PacketAuthenticatorSPI) Type() PacketAuthenticatorDRKeyType { - if p&(1<<13) == 0 { + if p&(1<<18) == 0 { return ASHost } return HostHost } func (p PacketAuthenticatorSPI) Direction() PacketAuthenticatorDRKeyDirection { - if p&(1<<14) == 0 { + if p&(1<<17) == 0 { return SenderSide } return ReceiverSide } func (p PacketAuthenticatorSPI) Epoch() PacketAuthenticatorDRKeyEpochType { - if p&(1<<15) == 0 { + if p&(1<<16) == 0 { return Later } return Earlier } func (p PacketAuthenticatorSPI) DRKeyProto() uint16 { - return uint16(p >> 16) + return uint16(p) } func (p PacketAuthenticatorSPI) IsDRKey() bool { @@ -521,10 +521,10 @@ func MakePacketAuthSPIDrkey( if epoch > 1 { panic("Invalid DRKeyEpochType value") } - spi := uint32((drkeyType & 0x1)) << 13 - spi |= uint32((dir & 0x1)) << 14 - spi |= uint32((epoch & 0x1)) << 15 - spi |= uint32(proto) << 16 + spi := uint32((drkeyType & 0x1)) << 18 + spi |= uint32((dir & 0x1)) << 17 + spi |= uint32((epoch & 0x1)) << 16 + spi |= uint32(proto) return PacketAuthenticatorSPI(spi) } @@ -602,7 +602,7 @@ func (o PacketAuthenticatorOption) Reset( } else { o.OptData = make([]byte, n) } - binary.LittleEndian.PutUint32(o.OptData[:4], uint32(spi)) + binary.BigEndian.PutUint32(o.OptData[:4], uint32(spi)) o.OptData[4] = byte(alg) o.OptData[5] = byte(ts >> 16) o.OptData[6] = byte(ts >> 8) @@ -621,7 +621,7 @@ func (o PacketAuthenticatorOption) Reset( // SPI returns returns the value set in the homonym field in the extension. func (o PacketAuthenticatorOption) SPI() PacketAuthenticatorSPI { - return PacketAuthenticatorSPI(binary.LittleEndian.Uint32(o.OptData[:4])) + return PacketAuthenticatorSPI(binary.BigEndian.Uint32(o.OptData[:4])) } // Algorithm returns the algorithm type stored in the data buffer. diff --git a/pkg/slayers/extn_test.go b/pkg/slayers/extn_test.go index a262cdee26..eb3bb1f38e 100644 --- a/pkg/slayers/extn_test.go +++ b/pkg/slayers/extn_test.go @@ -543,7 +543,11 @@ func prepRawPacketWithExtn(t *testing.T, extns ...slayers.L4ProtocolType) []byte return buf.Bytes() } -var spi = slayers.PacketAuthenticatorSPI(binary.LittleEndian.Uint32([]byte{0, 0x80, 1, 0})) +var spi = slayers.MakePacketAuthSPIDrkey( + 1, + slayers.ASHost, + slayers.ReceiverSide, + slayers.Later) var algo = slayers.PacketAuthSHA1_AES_CBC var ts = binary.LittleEndian.Uint32([]byte{1, 2, 3, 0}) var sn = binary.LittleEndian.Uint32([]byte{4, 5, 6, 0}) @@ -570,7 +574,7 @@ var optAuthMAC = []byte("16byte_mac_foooo") var rawE2EOptAuth = append( []byte{ 0x11, 0x7, 0x2, 0x1c, - 0x0, 0x80, 0x1, 0x0, + 0x0, 0x2, 0x0, 0x1, 0x1, 0x3, 0x2, 0x1, 0x0, 0x6, 0x5, 0x4, }, @@ -635,7 +639,6 @@ func TestOptAuthenticatorSerialize(t *testing.T) { b := gopacket.NewSerializeBuffer() opts := gopacket.SerializeOptions{FixLengths: true} assert.NoError(t, e2e.SerializeTo(b, opts), "SerializeTo") - assert.Equal(t, rawE2EOptAuth, b.Bytes(), "Raw Buffer") }) } @@ -654,6 +657,10 @@ func TestOptAuthenticatorDeserialize(t *testing.T) { auth, err := slayers.ParsePacketAuthenticatorOption(optAuth) require.NoError(t, err, "ParsePacketAuthenticatorOption") assert.Equal(t, spi, auth.SPI(), "SPI") + assert.Equal(t, slayers.ASHost, auth.SPI().Type()) + assert.Equal(t, slayers.ReceiverSide, auth.SPI().Direction()) + assert.Equal(t, slayers.Later, auth.SPI().Epoch()) + assert.Equal(t, true, auth.SPI().IsDRKey()) assert.Equal(t, algo, auth.Algorithm(), "Algorithm Type") assert.Equal(t, ts, auth.Timestamp(), "Timestamp") assert.Equal(t, sn, auth.SequenceNumber(), "Sequence Number") @@ -662,7 +669,7 @@ func TestOptAuthenticatorDeserialize(t *testing.T) { func TestMakePacketAuthSPIDrkey(t *testing.T) { spi := slayers.MakePacketAuthSPIDrkey(1, slayers.ASHost, slayers.SenderSide, slayers.Later) - assert.EqualValues(t, binary.LittleEndian.Uint32([]byte{0, 0, 1, 0}), spi) + assert.EqualValues(t, binary.BigEndian.Uint32([]byte{0, 0, 0, 1}), spi) } func TestOptAuthenticatorDeserializeCorrupt(t *testing.T) { From 3ca638e7ff204ede8b88633aa0185ab5fc45c5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Tue, 19 Jul 2022 18:29:20 +0200 Subject: [PATCH 08/11] r6 --- pkg/slayers/extn.go | 94 ++++++++++++++++++++-------------------- pkg/slayers/extn_test.go | 35 ++++++++------- 2 files changed, 67 insertions(+), 62 deletions(-) diff --git a/pkg/slayers/extn.go b/pkg/slayers/extn.go index 56021e34c4..68967ca83f 100644 --- a/pkg/slayers/extn.go +++ b/pkg/slayers/extn.go @@ -450,64 +450,64 @@ func (e *EndToEndExtnSkipper) NextLayerType() gopacket.LayerType { // PacketAuthSPI is the identifier for the key used for the // packet authentication option. DRKey values are in the // range [1, 2^21-1]. -type PacketAuthenticatorSPI uint32 +type PacketAuthSPI uint32 -type PacketAuthenticatorDRKeyType uint8 +type PacketAuthDRKeyType uint8 const ( - ASHost PacketAuthenticatorDRKeyType = iota - HostHost + PacketAuthASHost PacketAuthDRKeyType = iota + PacketAuthHostHost ) -type PacketAuthenticatorDRKeyDirection uint8 +type PacketAuthDRKeyDirection uint8 const ( - SenderSide PacketAuthenticatorDRKeyDirection = iota - ReceiverSide + PacketAuthSenderSide PacketAuthDRKeyDirection = iota + PacketAuthReceiverSide ) -type PacketAuthenticatorDRKeyEpochType uint8 +type PacketAuthDRKeyEpochType uint8 const ( - Later PacketAuthenticatorDRKeyEpochType = iota - Earlier + PacketAuthLater PacketAuthDRKeyEpochType = iota + PacketAuthEarlier ) -func (p PacketAuthenticatorSPI) Type() PacketAuthenticatorDRKeyType { +func (p PacketAuthSPI) Type() PacketAuthDRKeyType { if p&(1<<18) == 0 { - return ASHost + return PacketAuthASHost } - return HostHost + return PacketAuthHostHost } -func (p PacketAuthenticatorSPI) Direction() PacketAuthenticatorDRKeyDirection { +func (p PacketAuthSPI) Direction() PacketAuthDRKeyDirection { if p&(1<<17) == 0 { - return SenderSide + return PacketAuthSenderSide } - return ReceiverSide + return PacketAuthReceiverSide } -func (p PacketAuthenticatorSPI) Epoch() PacketAuthenticatorDRKeyEpochType { +func (p PacketAuthSPI) Epoch() PacketAuthDRKeyEpochType { if p&(1<<16) == 0 { - return Later + return PacketAuthLater } - return Earlier + return PacketAuthEarlier } -func (p PacketAuthenticatorSPI) DRKeyProto() uint16 { +func (p PacketAuthSPI) DRKeyProto() uint16 { return uint16(p) } -func (p PacketAuthenticatorSPI) IsDRKey() bool { +func (p PacketAuthSPI) IsDRKey() bool { return p > 0 && p < (1<<21) } -func MakePacketAuthSPIDrkey( +func MakePacketAuthSPIDRKey( proto uint16, - drkeyType PacketAuthenticatorDRKeyType, - dir PacketAuthenticatorDRKeyDirection, - epoch PacketAuthenticatorDRKeyEpochType, -) PacketAuthenticatorSPI { + drkeyType PacketAuthDRKeyType, + dir PacketAuthDRKeyDirection, + epoch PacketAuthDRKeyEpochType, +) PacketAuthSPI { if proto < 1 { panic("Invalid proto identifier value") @@ -526,7 +526,7 @@ func MakePacketAuthSPIDrkey( spi |= uint32((epoch & 0x1)) << 16 spi |= uint32(proto) - return PacketAuthenticatorSPI(spi) + return PacketAuthSPI(spi) } // PacketAuthAlg is the enumerator for authenticator algorithm types in the @@ -538,49 +538,49 @@ const ( PacketAuthSHA1_AES_CBC ) -// PacketAuthenticatorOption wraps an EndToEndOption of OptTypeAuthenticator. +// PacketAuthOption wraps an EndToEndOption of OptTypeAuthenticator. // This can be used to serialize and parse the internal structure of the packet authenticator // option. -type PacketAuthenticatorOption struct { +type PacketAuthOption struct { *EndToEndOption } -// NewPacketAuthenticatorOption creates a new EndToEndOption of +// NewPacketAuthOption creates a new EndToEndOption of // OptTypeAuthenticator, initialized with the given SPAO data. -func NewPacketAuthenticatorOption( - spi PacketAuthenticatorSPI, +func NewPacketAuthOption( + spi PacketAuthSPI, alg PacketAuthAlg, ts uint32, sn uint32, auth []byte, -) PacketAuthenticatorOption { +) PacketAuthOption { - o := PacketAuthenticatorOption{EndToEndOption: new(EndToEndOption)} + o := PacketAuthOption{EndToEndOption: new(EndToEndOption)} o.Reset(spi, alg, ts, sn, auth) return o } -// ParsePacketAuthenticatorOption parses o as a packet authenticator option. +// ParsePacketAuthOption parses o as a packet authenticator option. // Performs minimal checks to ensure that SPI, algorithm, timestamp, RSV, and // sequence number are set. // Checking the size and content of the Authenticator data must be done by the // caller. -func ParsePacketAuthenticatorOption(o *EndToEndOption) (PacketAuthenticatorOption, error) { +func ParsePacketAuthOption(o *EndToEndOption) (PacketAuthOption, error) { if o.OptType != OptTypeAuthenticator { - return PacketAuthenticatorOption{}, + return PacketAuthOption{}, serrors.New("wrong option type", "expected", OptTypeAuthenticator, "actual", o.OptType) } if len(o.OptData) < 12 { - return PacketAuthenticatorOption{}, + return PacketAuthOption{}, serrors.New("buffer too short", "expected", 12, "actual", len(o.OptData)) } - return PacketAuthenticatorOption{o}, nil + return PacketAuthOption{o}, nil } // Reset reinitializes the underlying EndToEndOption with the SPAO data. // Reuses the OptData buffer if it is of sufficient capacity. -func (o PacketAuthenticatorOption) Reset( - spi PacketAuthenticatorSPI, +func (o PacketAuthOption) Reset( + spi PacketAuthSPI, alg PacketAuthAlg, ts uint32, sn uint32, @@ -620,28 +620,28 @@ func (o PacketAuthenticatorOption) Reset( } // SPI returns returns the value set in the homonym field in the extension. -func (o PacketAuthenticatorOption) SPI() PacketAuthenticatorSPI { - return PacketAuthenticatorSPI(binary.BigEndian.Uint32(o.OptData[:4])) +func (o PacketAuthOption) SPI() PacketAuthSPI { + return PacketAuthSPI(binary.BigEndian.Uint32(o.OptData[:4])) } // Algorithm returns the algorithm type stored in the data buffer. -func (o PacketAuthenticatorOption) Algorithm() PacketAuthAlg { +func (o PacketAuthOption) Algorithm() PacketAuthAlg { return PacketAuthAlg(o.OptData[4]) } // Timestamp returns the value set in the homonym field in the extension. -func (o PacketAuthenticatorOption) Timestamp() uint32 { +func (o PacketAuthOption) Timestamp() uint32 { return uint32(o.OptData[5])<<16 + uint32(o.OptData[6])<<8 + uint32(o.OptData[7]) } // SequenceNumber returns the value set in the homonym field in the extension. -func (o PacketAuthenticatorOption) SequenceNumber() uint32 { +func (o PacketAuthOption) SequenceNumber() uint32 { return uint32(o.OptData[9])<<16 + uint32(o.OptData[10])<<8 + uint32(o.OptData[11]) } // Authenticator returns slice of the underlying auth buffer. // Changes to this slice will be reflected on the wire when // the extension is serialized. -func (o PacketAuthenticatorOption) Authenticator() []byte { +func (o PacketAuthOption) Authenticator() []byte { return o.OptData[12:] } diff --git a/pkg/slayers/extn_test.go b/pkg/slayers/extn_test.go index eb3bb1f38e..c7cbb5685c 100644 --- a/pkg/slayers/extn_test.go +++ b/pkg/slayers/extn_test.go @@ -543,11 +543,11 @@ func prepRawPacketWithExtn(t *testing.T, extns ...slayers.L4ProtocolType) []byte return buf.Bytes() } -var spi = slayers.MakePacketAuthSPIDrkey( +var spi = slayers.MakePacketAuthSPIDRKey( 1, - slayers.ASHost, - slayers.ReceiverSide, - slayers.Later) + slayers.PacketAuthASHost, + slayers.PacketAuthReceiverSide, + slayers.PacketAuthLater) var algo = slayers.PacketAuthSHA1_AES_CBC var ts = binary.LittleEndian.Uint32([]byte{1, 2, 3, 0}) var sn = binary.LittleEndian.Uint32([]byte{4, 5, 6, 0}) @@ -584,7 +584,7 @@ var rawE2EOptAuth = append( func TestOptAuthenticatorSerialize(t *testing.T) { cases := []struct { name string - spi slayers.PacketAuthenticatorSPI + spi slayers.PacketAuthSPI algo slayers.PacketAuthAlg ts uint32 sn uint32 @@ -623,14 +623,14 @@ func TestOptAuthenticatorSerialize(t *testing.T) { t.Run(c.name, func(t *testing.T) { if c.panics { assert.Panics(t, func() { - slayers.NewPacketAuthenticatorOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) + slayers.NewPacketAuthOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) }, "The code did not panic", ) return } - spao := slayers.NewPacketAuthenticatorOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) + spao := slayers.NewPacketAuthOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) e2e := slayers.EndToEndExtn{} e2e.NextHdr = slayers.L4UDP @@ -654,12 +654,12 @@ func TestOptAuthenticatorDeserialize(t *testing.T) { assert.Equal(t, slayers.L4UDP, e2e.NextHdr, "NextHeader") optAuth, err := e2e.FindOption(slayers.OptTypeAuthenticator) require.NoError(t, err, "FindOption") - auth, err := slayers.ParsePacketAuthenticatorOption(optAuth) - require.NoError(t, err, "ParsePacketAuthenticatorOption") + auth, err := slayers.ParsePacketAuthOption(optAuth) + require.NoError(t, err, "ParsePacketAuthOption") assert.Equal(t, spi, auth.SPI(), "SPI") - assert.Equal(t, slayers.ASHost, auth.SPI().Type()) - assert.Equal(t, slayers.ReceiverSide, auth.SPI().Direction()) - assert.Equal(t, slayers.Later, auth.SPI().Epoch()) + assert.Equal(t, slayers.PacketAuthASHost, auth.SPI().Type()) + assert.Equal(t, slayers.PacketAuthReceiverSide, auth.SPI().Direction()) + assert.Equal(t, slayers.PacketAuthLater, auth.SPI().Epoch()) assert.Equal(t, true, auth.SPI().IsDRKey()) assert.Equal(t, algo, auth.Algorithm(), "Algorithm Type") assert.Equal(t, ts, auth.Timestamp(), "Timestamp") @@ -668,7 +668,12 @@ func TestOptAuthenticatorDeserialize(t *testing.T) { } func TestMakePacketAuthSPIDrkey(t *testing.T) { - spi := slayers.MakePacketAuthSPIDrkey(1, slayers.ASHost, slayers.SenderSide, slayers.Later) + spi := slayers.MakePacketAuthSPIDRKey( + 1, + slayers.PacketAuthASHost, + slayers.PacketAuthSenderSide, + slayers.PacketAuthLater, + ) assert.EqualValues(t, binary.BigEndian.Uint32([]byte{0, 0, 0, 1}), spi) } @@ -688,6 +693,6 @@ func TestOptAuthenticatorDeserializeCorrupt(t *testing.T) { assert.NoError(t, e2e.DecodeFromBytes(b.Bytes(), gopacket.NilDecodeFeedback)) optAuth, err := e2e.FindOption(slayers.OptTypeAuthenticator) require.NoError(t, err, "FindOption") - _, err = slayers.ParsePacketAuthenticatorOption(optAuth) - require.Error(t, err, "ParsePacketAuthenticatorOption should fail") + _, err = slayers.ParsePacketAuthOption(optAuth) + require.Error(t, err, "ParsePacketAuthOption should fail") } From f91e9ec9561a3e69e8e6654970cbe6910d8331df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Mon, 5 Sep 2022 12:24:16 +0200 Subject: [PATCH 09/11] r7 --- pkg/slayers/BUILD.bazel | 2 + pkg/slayers/extn.go | 200 ------------------------------- pkg/slayers/extn_test.go | 155 ------------------------ pkg/slayers/pkt_auth.go | 221 +++++++++++++++++++++++++++++++++++ pkg/slayers/pkt_auth_test.go | 184 +++++++++++++++++++++++++++++ 5 files changed, 407 insertions(+), 355 deletions(-) create mode 100644 pkg/slayers/pkt_auth.go create mode 100644 pkg/slayers/pkt_auth_test.go diff --git a/pkg/slayers/BUILD.bazel b/pkg/slayers/BUILD.bazel index 8796f3e948..232d4b3420 100644 --- a/pkg/slayers/BUILD.bazel +++ b/pkg/slayers/BUILD.bazel @@ -7,6 +7,7 @@ go_library( "extn.go", "l4.go", "layertypes.go", + "pkt_auth.go", "scion.go", "scmp.go", "scmp_msg.go", @@ -33,6 +34,7 @@ go_test( "bfd_test.go", "export_test.go", "extn_test.go", + "pkt_auth_test.go", "scion_test.go", "scmp_msg_test.go", "scmp_test.go", diff --git a/pkg/slayers/extn.go b/pkg/slayers/extn.go index 68967ca83f..d86c405a6b 100644 --- a/pkg/slayers/extn.go +++ b/pkg/slayers/extn.go @@ -15,7 +15,6 @@ package slayers import ( - "encoding/binary" "fmt" "github.com/google/gopacket" @@ -446,202 +445,3 @@ func (s *EndToEndExtnSkipper) CanDecode() gopacket.LayerClass { func (e *EndToEndExtnSkipper) NextLayerType() gopacket.LayerType { return scionNextLayerTypeAfterE2E(e.NextHdr) } - -// PacketAuthSPI is the identifier for the key used for the -// packet authentication option. DRKey values are in the -// range [1, 2^21-1]. -type PacketAuthSPI uint32 - -type PacketAuthDRKeyType uint8 - -const ( - PacketAuthASHost PacketAuthDRKeyType = iota - PacketAuthHostHost -) - -type PacketAuthDRKeyDirection uint8 - -const ( - PacketAuthSenderSide PacketAuthDRKeyDirection = iota - PacketAuthReceiverSide -) - -type PacketAuthDRKeyEpochType uint8 - -const ( - PacketAuthLater PacketAuthDRKeyEpochType = iota - PacketAuthEarlier -) - -func (p PacketAuthSPI) Type() PacketAuthDRKeyType { - if p&(1<<18) == 0 { - return PacketAuthASHost - } - return PacketAuthHostHost -} - -func (p PacketAuthSPI) Direction() PacketAuthDRKeyDirection { - if p&(1<<17) == 0 { - return PacketAuthSenderSide - } - return PacketAuthReceiverSide -} - -func (p PacketAuthSPI) Epoch() PacketAuthDRKeyEpochType { - if p&(1<<16) == 0 { - return PacketAuthLater - } - return PacketAuthEarlier -} - -func (p PacketAuthSPI) DRKeyProto() uint16 { - return uint16(p) -} - -func (p PacketAuthSPI) IsDRKey() bool { - return p > 0 && p < (1<<21) -} - -func MakePacketAuthSPIDRKey( - proto uint16, - drkeyType PacketAuthDRKeyType, - dir PacketAuthDRKeyDirection, - epoch PacketAuthDRKeyEpochType, -) PacketAuthSPI { - - if proto < 1 { - panic("Invalid proto identifier value") - } - if drkeyType > 1 { - panic("Invalid DRKeyType value") - } - if dir > 1 { - panic("Invalid DRKeyDirection value") - } - if epoch > 1 { - panic("Invalid DRKeyEpochType value") - } - spi := uint32((drkeyType & 0x1)) << 18 - spi |= uint32((dir & 0x1)) << 17 - spi |= uint32((epoch & 0x1)) << 16 - spi |= uint32(proto) - - return PacketAuthSPI(spi) -} - -// PacketAuthAlg is the enumerator for authenticator algorithm types in the -// packet authenticator option. -type PacketAuthAlg uint8 - -const ( - PacketAuthCMAC PacketAuthAlg = iota - PacketAuthSHA1_AES_CBC -) - -// PacketAuthOption wraps an EndToEndOption of OptTypeAuthenticator. -// This can be used to serialize and parse the internal structure of the packet authenticator -// option. -type PacketAuthOption struct { - *EndToEndOption -} - -// NewPacketAuthOption creates a new EndToEndOption of -// OptTypeAuthenticator, initialized with the given SPAO data. -func NewPacketAuthOption( - spi PacketAuthSPI, - alg PacketAuthAlg, - ts uint32, - sn uint32, - auth []byte, -) PacketAuthOption { - - o := PacketAuthOption{EndToEndOption: new(EndToEndOption)} - o.Reset(spi, alg, ts, sn, auth) - return o -} - -// ParsePacketAuthOption parses o as a packet authenticator option. -// Performs minimal checks to ensure that SPI, algorithm, timestamp, RSV, and -// sequence number are set. -// Checking the size and content of the Authenticator data must be done by the -// caller. -func ParsePacketAuthOption(o *EndToEndOption) (PacketAuthOption, error) { - if o.OptType != OptTypeAuthenticator { - return PacketAuthOption{}, - serrors.New("wrong option type", "expected", OptTypeAuthenticator, "actual", o.OptType) - } - if len(o.OptData) < 12 { - return PacketAuthOption{}, - serrors.New("buffer too short", "expected", 12, "actual", len(o.OptData)) - } - return PacketAuthOption{o}, nil -} - -// Reset reinitializes the underlying EndToEndOption with the SPAO data. -// Reuses the OptData buffer if it is of sufficient capacity. -func (o PacketAuthOption) Reset( - spi PacketAuthSPI, - alg PacketAuthAlg, - ts uint32, - sn uint32, - auth []byte, -) { - - if ts >= (1 << 24) { - panic("Timestamp value should be smaller than 2^24") - } - if sn >= (1 << 24) { - panic("Sequence number should be smaller than 2^24") - } - - o.OptType = OptTypeAuthenticator - - n := 12 + len(auth) // 4 + 1 + 3 + 1 + 3 + len(data) - if n <= cap(o.OptData) { - o.OptData = o.OptData[:n] - } else { - o.OptData = make([]byte, n) - } - binary.BigEndian.PutUint32(o.OptData[:4], uint32(spi)) - o.OptData[4] = byte(alg) - o.OptData[5] = byte(ts >> 16) - o.OptData[6] = byte(ts >> 8) - o.OptData[7] = byte(ts) - o.OptData[8] = byte(0) - o.OptData[9] = byte(sn >> 16) - o.OptData[10] = byte(sn >> 8) - o.OptData[11] = byte(sn) - copy(o.OptData[12:], auth) - - o.OptAlign = [2]uint8{4, 2} - // reset unused/implicit fields - o.OptDataLen = 0 - o.ActualLength = 0 -} - -// SPI returns returns the value set in the homonym field in the extension. -func (o PacketAuthOption) SPI() PacketAuthSPI { - return PacketAuthSPI(binary.BigEndian.Uint32(o.OptData[:4])) -} - -// Algorithm returns the algorithm type stored in the data buffer. -func (o PacketAuthOption) Algorithm() PacketAuthAlg { - return PacketAuthAlg(o.OptData[4]) -} - -// Timestamp returns the value set in the homonym field in the extension. -func (o PacketAuthOption) Timestamp() uint32 { - return uint32(o.OptData[5])<<16 + uint32(o.OptData[6])<<8 + uint32(o.OptData[7]) -} - -// SequenceNumber returns the value set in the homonym field in the extension. -func (o PacketAuthOption) SequenceNumber() uint32 { - return uint32(o.OptData[9])<<16 + uint32(o.OptData[10])<<8 + uint32(o.OptData[11]) -} - -// Authenticator returns slice of the underlying auth buffer. -// Changes to this slice will be reflected on the wire when -// the extension is serialized. -func (o PacketAuthOption) Authenticator() []byte { - return o.OptData[12:] -} diff --git a/pkg/slayers/extn_test.go b/pkg/slayers/extn_test.go index c7cbb5685c..4283394b5f 100644 --- a/pkg/slayers/extn_test.go +++ b/pkg/slayers/extn_test.go @@ -15,7 +15,6 @@ package slayers_test import ( - "encoding/binary" "fmt" "testing" @@ -542,157 +541,3 @@ func prepRawPacketWithExtn(t *testing.T, extns ...slayers.L4ProtocolType) []byte return buf.Bytes() } - -var spi = slayers.MakePacketAuthSPIDRKey( - 1, - slayers.PacketAuthASHost, - slayers.PacketAuthReceiverSide, - slayers.PacketAuthLater) -var algo = slayers.PacketAuthSHA1_AES_CBC -var ts = binary.LittleEndian.Uint32([]byte{1, 2, 3, 0}) -var sn = binary.LittleEndian.Uint32([]byte{4, 5, 6, 0}) -var optAuthMAC = []byte("16byte_mac_foooo") - -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | NextHdr=UDP | ExtLen | OptType=2 | OptDataLen | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Security Parameter Index | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Algorithm | Timestamp | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | RSV | Sequence Number | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | | -// + + -// | | -// + 16-octet MAC data + -// | | -// + + -// | | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -var rawE2EOptAuth = append( - []byte{ - 0x11, 0x7, 0x2, 0x1c, - 0x0, 0x2, 0x0, 0x1, - 0x1, 0x3, 0x2, 0x1, - 0x0, 0x6, 0x5, 0x4, - }, - optAuthMAC..., -) - -func TestOptAuthenticatorSerialize(t *testing.T) { - cases := []struct { - name string - spi slayers.PacketAuthSPI - algo slayers.PacketAuthAlg - ts uint32 - sn uint32 - optAuth []byte - panics bool - }{ - { - name: "correct", - spi: spi, - algo: algo, - ts: ts, - sn: sn, - optAuth: optAuthMAC, - panics: false, - }, - { - name: "bad_ts", - spi: spi, - algo: algo, - ts: binary.LittleEndian.Uint32([]byte{0, 0, 0, 1}), - sn: sn, - optAuth: optAuthMAC, - panics: true, - }, - { - name: "bad_sn", - spi: spi, - algo: algo, - ts: ts, - sn: binary.LittleEndian.Uint32([]byte{0, 0, 0, 1}), - optAuth: optAuthMAC, - panics: true, - }, - } - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - if c.panics { - assert.Panics(t, func() { - slayers.NewPacketAuthOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) - }, - "The code did not panic", - ) - return - } - - spao := slayers.NewPacketAuthOption(c.spi, c.algo, c.ts, c.sn, c.optAuth) - - e2e := slayers.EndToEndExtn{} - e2e.NextHdr = slayers.L4UDP - e2e.Options = []*slayers.EndToEndOption{spao.EndToEndOption} - - b := gopacket.NewSerializeBuffer() - opts := gopacket.SerializeOptions{FixLengths: true} - assert.NoError(t, e2e.SerializeTo(b, opts), "SerializeTo") - assert.Equal(t, rawE2EOptAuth, b.Bytes(), "Raw Buffer") - }) - } -} - -func TestOptAuthenticatorDeserialize(t *testing.T) { - e2e := slayers.EndToEndExtn{} - - _, err := e2e.FindOption(slayers.OptTypeAuthenticator) - assert.Error(t, err) - - assert.NoError(t, e2e.DecodeFromBytes(rawE2EOptAuth, gopacket.NilDecodeFeedback)) - assert.Equal(t, slayers.L4UDP, e2e.NextHdr, "NextHeader") - optAuth, err := e2e.FindOption(slayers.OptTypeAuthenticator) - require.NoError(t, err, "FindOption") - auth, err := slayers.ParsePacketAuthOption(optAuth) - require.NoError(t, err, "ParsePacketAuthOption") - assert.Equal(t, spi, auth.SPI(), "SPI") - assert.Equal(t, slayers.PacketAuthASHost, auth.SPI().Type()) - assert.Equal(t, slayers.PacketAuthReceiverSide, auth.SPI().Direction()) - assert.Equal(t, slayers.PacketAuthLater, auth.SPI().Epoch()) - assert.Equal(t, true, auth.SPI().IsDRKey()) - assert.Equal(t, algo, auth.Algorithm(), "Algorithm Type") - assert.Equal(t, ts, auth.Timestamp(), "Timestamp") - assert.Equal(t, sn, auth.SequenceNumber(), "Sequence Number") - assert.Equal(t, optAuthMAC, auth.Authenticator(), "Authenticator data (MAC)") -} - -func TestMakePacketAuthSPIDrkey(t *testing.T) { - spi := slayers.MakePacketAuthSPIDRKey( - 1, - slayers.PacketAuthASHost, - slayers.PacketAuthSenderSide, - slayers.PacketAuthLater, - ) - assert.EqualValues(t, binary.BigEndian.Uint32([]byte{0, 0, 0, 1}), spi) -} - -func TestOptAuthenticatorDeserializeCorrupt(t *testing.T) { - optAuthCorrupt := slayers.EndToEndOption{ - OptType: slayers.OptTypeAuthenticator, - OptData: []byte{}, - } - e2e := slayers.EndToEndExtn{} - e2e.NextHdr = slayers.L4UDP - e2e.Options = []*slayers.EndToEndOption{&optAuthCorrupt} - - b := gopacket.NewSerializeBuffer() - opts := gopacket.SerializeOptions{FixLengths: true} - assert.NoError(t, e2e.SerializeTo(b, opts), "SerializeTo") - - assert.NoError(t, e2e.DecodeFromBytes(b.Bytes(), gopacket.NilDecodeFeedback)) - optAuth, err := e2e.FindOption(slayers.OptTypeAuthenticator) - require.NoError(t, err, "FindOption") - _, err = slayers.ParsePacketAuthOption(optAuth) - require.Error(t, err, "ParsePacketAuthOption should fail") -} diff --git a/pkg/slayers/pkt_auth.go b/pkg/slayers/pkt_auth.go new file mode 100644 index 0000000000..48e1f80922 --- /dev/null +++ b/pkg/slayers/pkt_auth.go @@ -0,0 +1,221 @@ +// Copyright 2022 ETH Zurich +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file includes the SPAO header implementation as specified +// in https://scion.docs.anapaya.net/en/latest/protocols/authenticator-option.html + +package slayers + +import ( + "encoding/binary" + + "github.com/scionproto/scion/pkg/private/serrors" +) + +const ( + PacketAuthASHost uint8 = iota + PacketAuthHostHost +) + +const ( + PacketAuthSenderSide uint8 = iota + PacketAuthReceiverSide +) + +const ( + PacketAuthLater uint8 = iota + PacketAuthEarlier +) + +// MinOptDataLen is the minimum size of the SPAO OptData +const MinOptDataLen = 12 + +// PacketAuthSPI (Security Parameter Index) is the identifier for the key +// used for the packet authentication option. DRKey values are in the +// range [1, 2^21-1]. +type PacketAuthSPI uint32 + +func (p PacketAuthSPI) Type() uint8 { + if p&(1<<18) == 0 { + return PacketAuthASHost + } + return PacketAuthHostHost +} + +func (p PacketAuthSPI) Direction() uint8 { + if p&(1<<17) == 0 { + return PacketAuthSenderSide + } + return PacketAuthReceiverSide +} + +func (p PacketAuthSPI) Epoch() uint8 { + if p&(1<<16) == 0 { + return PacketAuthLater + } + return PacketAuthEarlier +} + +func (p PacketAuthSPI) DRKeyProto() uint16 { + return uint16(p) +} + +func (p PacketAuthSPI) IsDRKey() bool { + return p > 0 && p < (1<<21) +} + +func MakePacketAuthSPIDRKey( + proto uint16, + drkeyType uint8, + dir uint8, + epoch uint8, +) (PacketAuthSPI, error) { + + if proto < 1 { + return 0, serrors.New("Invalid proto identifier value") + } + if drkeyType > 1 { + return 0, serrors.New("Invalid DRKeyType value") + } + if dir > 1 { + return 0, serrors.New("Invalid DRKeyDirection value") + } + if epoch > 1 { + return 0, serrors.New("Invalid DRKeyEpochType value") + } + spi := uint32((drkeyType & 0x1)) << 18 + spi |= uint32((dir & 0x1)) << 17 + spi |= uint32((epoch & 0x1)) << 16 + spi |= uint32(proto) + + return PacketAuthSPI(spi), nil +} + +// PacketAuthAlg is the enumerator for authenticator algorithm types in the +// packet authenticator option. +type PacketAuthAlg uint8 + +const ( + PacketAuthCMAC PacketAuthAlg = iota + PacketAuthSHA1_AES_CBC +) + +type PacketAuthOptionParams struct { + SPI PacketAuthSPI + Algorithm PacketAuthAlg + Timestamp uint32 + SequenceNumber uint32 + Auth []byte +} + +// PacketAuthOption wraps an EndToEndOption of OptTypeAuthenticator. +// This can be used to serialize and parse the internal structure of the packet authenticator +// option. +type PacketAuthOption struct { + *EndToEndOption +} + +// NewPacketAuthOption creates a new EndToEndOption of +// OptTypeAuthenticator, initialized with the given SPAO data. +func NewPacketAuthOption( + p PacketAuthOptionParams, +) (PacketAuthOption, error) { + + o := PacketAuthOption{EndToEndOption: new(EndToEndOption)} + err := o.Reset(p) + return o, err +} + +// ParsePacketAuthOption parses o as a packet authenticator option. +// Performs minimal checks to ensure that SPI, algorithm, timestamp, RSV, and +// sequence number are set. +// Checking the size and content of the Authenticator data must be done by the +// caller. +func ParsePacketAuthOption(o *EndToEndOption) (PacketAuthOption, error) { + if o.OptType != OptTypeAuthenticator { + return PacketAuthOption{}, + serrors.New("wrong option type", "expected", OptTypeAuthenticator, "actual", o.OptType) + } + if len(o.OptData) < MinOptDataLen { + return PacketAuthOption{}, + serrors.New("buffer too short", "expected at least", 12, "actual", len(o.OptData)) + } + return PacketAuthOption{o}, nil +} + +// Reset reinitializes the underlying EndToEndOption with the SPAO data. +// Reuses the OptData buffer if it is of sufficient capacity. +func (o PacketAuthOption) Reset( + p PacketAuthOptionParams, +) error { + + if p.Timestamp >= (1 << 24) { + return serrors.New("Timestamp value should be smaller than 2^24") + } + if p.SequenceNumber >= (1 << 24) { + return serrors.New("Sequence number should be smaller than 2^24") + } + + o.OptType = OptTypeAuthenticator + + n := 12 + len(p.Auth) // 4 + 1 + 3 + 1 + 3 + len(data) + if n <= cap(o.OptData) { + o.OptData = o.OptData[:n] + } else { + o.OptData = make([]byte, n) + } + binary.BigEndian.PutUint32(o.OptData[:4], uint32(p.SPI)) + o.OptData[4] = byte(p.Algorithm) + o.OptData[5] = byte(p.Timestamp >> 16) + o.OptData[6] = byte(p.Timestamp >> 8) + o.OptData[7] = byte(p.Timestamp) + o.OptData[8] = byte(0) + o.OptData[9] = byte(p.SequenceNumber >> 16) + o.OptData[10] = byte(p.SequenceNumber >> 8) + o.OptData[11] = byte(p.SequenceNumber) + copy(o.OptData[12:], p.Auth) + + o.OptAlign = [2]uint8{4, 2} + // reset unused/implicit fields + o.OptDataLen = 0 + o.ActualLength = 0 + return nil +} + +// SPI returns the value set in the Security Parameter Index in the extension. +func (o PacketAuthOption) SPI() PacketAuthSPI { + return PacketAuthSPI(binary.BigEndian.Uint32(o.OptData[:4])) +} + +// Algorithm returns the algorithm type stored in the data buffer. +func (o PacketAuthOption) Algorithm() PacketAuthAlg { + return PacketAuthAlg(o.OptData[4]) +} + +// Timestamp returns the value set in the homonym field in the extension. +func (o PacketAuthOption) Timestamp() uint32 { + return uint32(o.OptData[5])<<16 + uint32(o.OptData[6])<<8 + uint32(o.OptData[7]) +} + +// SequenceNumber returns the value set in the homonym field in the extension. +func (o PacketAuthOption) SequenceNumber() uint32 { + return uint32(o.OptData[9])<<16 + uint32(o.OptData[10])<<8 + uint32(o.OptData[11]) +} + +// Authenticator returns slice of the underlying auth buffer. +// Changes to this slice will be reflected on the wire when +// the extension is serialized. +func (o PacketAuthOption) Authenticator() []byte { + return o.OptData[12:] +} diff --git a/pkg/slayers/pkt_auth_test.go b/pkg/slayers/pkt_auth_test.go new file mode 100644 index 0000000000..8a2701c008 --- /dev/null +++ b/pkg/slayers/pkt_auth_test.go @@ -0,0 +1,184 @@ +// Copyright 2022 ETH Zurich +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package slayers_test + +import ( + "encoding/binary" + "testing" + + "github.com/google/gopacket" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/scionproto/scion/pkg/slayers" +) + +var ( + algo = slayers.PacketAuthSHA1_AES_CBC + ts = binary.LittleEndian.Uint32([]byte{1, 2, 3, 0}) + sn = binary.LittleEndian.Uint32([]byte{4, 5, 6, 0}) + optAuthMAC = []byte("16byte_mac_foooo") +) + +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | NextHdr=UDP | ExtLen | OptType=2 | OptDataLen | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Security Parameter Index | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Algorithm | Timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | RSV | Sequence Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// + + +// | | +// + 16-octet MAC data + +// | | +// + + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +var rawE2EOptAuth = append( + []byte{ + 0x11, 0x7, 0x2, 0x1c, + 0x0, 0x2, 0x0, 0x1, + 0x1, 0x3, 0x2, 0x1, + 0x0, 0x6, 0x5, 0x4, + }, + optAuthMAC..., +) + +func TestOptAuthenticatorSerialize(t *testing.T) { + cases := []struct { + name string + spiFunc func(t *testing.T) slayers.PacketAuthSPI + algo slayers.PacketAuthAlg + ts uint32 + sn uint32 + optAuth []byte + errorFunc assert.ErrorAssertionFunc + }{ + { + name: "correct", + spiFunc: initSPI, + algo: algo, + ts: ts, + sn: sn, + optAuth: optAuthMAC, + errorFunc: assert.NoError, + }, + { + name: "bad_ts", + spiFunc: initSPI, + algo: algo, + ts: binary.LittleEndian.Uint32([]byte{0, 0, 0, 1}), + sn: sn, + optAuth: optAuthMAC, + errorFunc: assert.Error, + }, + { + name: "bad_sn", + spiFunc: initSPI, + algo: algo, + ts: ts, + sn: binary.LittleEndian.Uint32([]byte{0, 0, 0, 1}), + optAuth: optAuthMAC, + errorFunc: assert.Error, + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + + spao, err := slayers.NewPacketAuthOption(slayers.PacketAuthOptionParams{ + SPI: c.spiFunc(t), + Algorithm: c.algo, + Timestamp: c.ts, + SequenceNumber: c.sn, + Auth: c.optAuth, + }) + c.errorFunc(t, err) + if err != nil { + return + } + + e2e := slayers.EndToEndExtn{} + e2e.NextHdr = slayers.L4UDP + e2e.Options = []*slayers.EndToEndOption{spao.EndToEndOption} + + b := gopacket.NewSerializeBuffer() + opts := gopacket.SerializeOptions{FixLengths: true} + assert.NoError(t, e2e.SerializeTo(b, opts), "SerializeTo") + assert.Equal(t, rawE2EOptAuth, b.Bytes(), "Raw Buffer") + }) + } +} + +func TestOptAuthenticatorDeserialize(t *testing.T) { + e2e := slayers.EndToEndExtn{} + + _, err := e2e.FindOption(slayers.OptTypeAuthenticator) + assert.Error(t, err) + + assert.NoError(t, e2e.DecodeFromBytes(rawE2EOptAuth, gopacket.NilDecodeFeedback)) + assert.Equal(t, slayers.L4UDP, e2e.NextHdr, "NextHeader") + optAuth, err := e2e.FindOption(slayers.OptTypeAuthenticator) + require.NoError(t, err, "FindOption") + auth, err := slayers.ParsePacketAuthOption(optAuth) + require.NoError(t, err, "ParsePacketAuthOption") + assert.Equal(t, initSPI(t), auth.SPI(), "SPI") + assert.Equal(t, slayers.PacketAuthASHost, auth.SPI().Type()) + assert.Equal(t, slayers.PacketAuthReceiverSide, auth.SPI().Direction()) + assert.Equal(t, slayers.PacketAuthLater, auth.SPI().Epoch()) + assert.Equal(t, true, auth.SPI().IsDRKey()) + assert.Equal(t, algo, auth.Algorithm(), "Algorithm Type") + assert.Equal(t, ts, auth.Timestamp(), "Timestamp") + assert.Equal(t, sn, auth.SequenceNumber(), "Sequence Number") + assert.Equal(t, optAuthMAC, auth.Authenticator(), "Authenticator data (MAC)") +} + +func TestMakePacketAuthSPIDrkey(t *testing.T) { + spi := initSPI(t) + assert.EqualValues(t, binary.BigEndian.Uint32([]byte{0, 2, 0, 1}), spi) +} + +func TestOptAuthenticatorDeserializeCorrupt(t *testing.T) { + optAuthCorrupt := slayers.EndToEndOption{ + OptType: slayers.OptTypeAuthenticator, + OptData: []byte{}, + } + e2e := slayers.EndToEndExtn{} + e2e.NextHdr = slayers.L4UDP + e2e.Options = []*slayers.EndToEndOption{&optAuthCorrupt} + + b := gopacket.NewSerializeBuffer() + opts := gopacket.SerializeOptions{FixLengths: true} + assert.NoError(t, e2e.SerializeTo(b, opts), "SerializeTo") + + assert.NoError(t, e2e.DecodeFromBytes(b.Bytes(), gopacket.NilDecodeFeedback)) + optAuth, err := e2e.FindOption(slayers.OptTypeAuthenticator) + require.NoError(t, err, "FindOption") + _, err = slayers.ParsePacketAuthOption(optAuth) + require.Error(t, err, "ParsePacketAuthOption should fail") +} + +func initSPI(t *testing.T) slayers.PacketAuthSPI { + spi, err := slayers.MakePacketAuthSPIDRKey( + 1, + slayers.PacketAuthASHost, + slayers.PacketAuthReceiverSide, + slayers.PacketAuthLater) + require.NoError(t, err) + return spi +} From 74e088d0cfd551d1ca37a683900b8fa6e0aa4183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Fri, 9 Sep 2022 10:52:15 +0200 Subject: [PATCH 10/11] r8 --- pkg/slayers/pkt_auth.go | 30 ++++++++++++++++++++++++++---- pkg/slayers/pkt_auth_test.go | 18 ------------------ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/pkg/slayers/pkt_auth.go b/pkg/slayers/pkt_auth.go index 48e1f80922..d4b1ce3900 100644 --- a/pkg/slayers/pkt_auth.go +++ b/pkg/slayers/pkt_auth.go @@ -15,6 +15,25 @@ // This file includes the SPAO header implementation as specified // in https://scion.docs.anapaya.net/en/latest/protocols/authenticator-option.html +// The Authenticator option format is as follows: +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | NextHdr=UDP | ExtLen | OptType=2 | OptDataLen | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Security Parameter Index | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Algorithm | Timestamp | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | RSV | Sequence Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// + + +// | | +// + 16-octet MAC data + +// | | +// + + +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + package slayers import ( @@ -38,8 +57,11 @@ const ( PacketAuthEarlier ) -// MinOptDataLen is the minimum size of the SPAO OptData -const MinOptDataLen = 12 +// MinPacketAuthDataLen is the minimum size of the SPAO OptData. +// The SPAO header contains the following fixed-length fields: +// SPI (4 Bytes), Algorithm (1 Byte), Timestamp (3Bytes), +// RSV (1 Byte) and Sequence Number (3 Bytes). +const MinPacketAuthDataLen = 12 // PacketAuthSPI (Security Parameter Index) is the identifier for the key // used for the packet authentication option. DRKey values are in the @@ -147,7 +169,7 @@ func ParsePacketAuthOption(o *EndToEndOption) (PacketAuthOption, error) { return PacketAuthOption{}, serrors.New("wrong option type", "expected", OptTypeAuthenticator, "actual", o.OptType) } - if len(o.OptData) < MinOptDataLen { + if len(o.OptData) < MinPacketAuthDataLen { return PacketAuthOption{}, serrors.New("buffer too short", "expected at least", 12, "actual", len(o.OptData)) } @@ -169,7 +191,7 @@ func (o PacketAuthOption) Reset( o.OptType = OptTypeAuthenticator - n := 12 + len(p.Auth) // 4 + 1 + 3 + 1 + 3 + len(data) + n := MinPacketAuthDataLen + len(p.Auth) if n <= cap(o.OptData) { o.OptData = o.OptData[:n] } else { diff --git a/pkg/slayers/pkt_auth_test.go b/pkg/slayers/pkt_auth_test.go index 8a2701c008..98e36fef43 100644 --- a/pkg/slayers/pkt_auth_test.go +++ b/pkg/slayers/pkt_auth_test.go @@ -32,24 +32,6 @@ var ( optAuthMAC = []byte("16byte_mac_foooo") ) -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | NextHdr=UDP | ExtLen | OptType=2 | OptDataLen | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Security Parameter Index | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | Algorithm | Timestamp | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | RSV | Sequence Number | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | | -// + + -// | | -// + 16-octet MAC data + -// | | -// + + -// | | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - var rawE2EOptAuth = append( []byte{ 0x11, 0x7, 0x2, 0x1c, From d04fd6b7ea43df3fdab672ce16d846e1e802d451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jordi=20Subir=C3=A0=20Nieto?= Date: Fri, 9 Sep 2022 10:55:39 +0200 Subject: [PATCH 11/11] r8.1 --- pkg/slayers/pkt_auth.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/slayers/pkt_auth.go b/pkg/slayers/pkt_auth.go index d4b1ce3900..9358f4e5a0 100644 --- a/pkg/slayers/pkt_auth.go +++ b/pkg/slayers/pkt_auth.go @@ -59,7 +59,7 @@ const ( // MinPacketAuthDataLen is the minimum size of the SPAO OptData. // The SPAO header contains the following fixed-length fields: -// SPI (4 Bytes), Algorithm (1 Byte), Timestamp (3Bytes), +// SPI (4 Bytes), Algorithm (1 Byte), Timestamp (3 Bytes), // RSV (1 Byte) and Sequence Number (3 Bytes). const MinPacketAuthDataLen = 12