Skip to content

Commit

Permalink
Update SPAO extension header (scionproto#4190)
Browse files Browse the repository at this point in the history
This PR updates the SCION Packet Authenticator Option (SPAO) to be compliant with the current specification (https://docs.scion.net/en/latest/protocols/authenticator-option.html).
  • Loading branch information
JordiSubira authored and benthor committed Nov 24, 2022
1 parent 64c4d18 commit 944972e
Show file tree
Hide file tree
Showing 5 changed files with 411 additions and 146 deletions.
2 changes: 2 additions & 0 deletions pkg/slayers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ go_library(
"extn.go",
"l4.go",
"layertypes.go",
"pkt_auth.go",
"scion.go",
"scmp.go",
"scmp_msg.go",
Expand All @@ -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",
Expand Down
73 changes: 0 additions & 73 deletions pkg/slayers/extn.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,76 +445,3 @@ func (s *EndToEndExtnSkipper) CanDecode() gopacket.LayerClass {
func (e *EndToEndExtnSkipper) NextLayerType() gopacket.LayerType {
return scionNextLayerTypeAfterE2E(e.NextHdr)
}

// PacketAuthAlg is the enumerator for authenticator algorithm types in the
// packet authenticator option.
type PacketAuthAlg uint8

const (
PacketAuthCMAC PacketAuthAlg = 0
)

// PacketAuthenticatorOption wraps an EndToEndOption of OptTypeAuthenticator.
// This can be used to serialize and parse the internal structure of the packet authenticator
// option.
type PacketAuthenticatorOption struct {
*EndToEndOption
}

// NewPacketAuthenticatorOption creates a new EndToEndOption of
// OptTypeAuthenticator, initialized with the given algorithm type and
// authenticator data.
func NewPacketAuthenticatorOption(alg PacketAuthAlg, data []byte) PacketAuthenticatorOption {
o := PacketAuthenticatorOption{EndToEndOption: new(EndToEndOption)}
o.Reset(alg, data)
return o
}

// ParsePacketAuthenticatorOption parses o as a packet authenticator option.
// Performs minimal checks to ensure that Algorithm and Authenticator are set.
// Checking the size and content of the Authenticator data must be done by the
// caller.
func ParsePacketAuthenticatorOption(o *EndToEndOption) (PacketAuthenticatorOption, error) {
if o.OptType != OptTypeAuthenticator {
return PacketAuthenticatorOption{},
serrors.New("wrong option type", "expected", OptTypeAuthenticator, "actual", o.OptType)
}
if len(o.OptData) < 2 {
return PacketAuthenticatorOption{},
serrors.New("buffer too short", "expected", 2, "actual", len(o.OptData))
}
return PacketAuthenticatorOption{o}, nil
}

// Reset reinitializes the underlying EndToEndOption with the given algorithm
// type and authenticator data.
// Reuses the OptData buffer if it is of sufficient capacity.
func (o PacketAuthenticatorOption) Reset(alg PacketAuthAlg, data []byte) {
o.OptType = OptTypeAuthenticator

n := 1 + 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}
// reset unused/implicit fields
o.OptDataLen = 0
o.ActualLength = 0
}

// Algorithm returns the algorithm type stored in the data buffer.
func (o PacketAuthenticatorOption) Algorithm() PacketAuthAlg {
return PacketAuthAlg(o.OptData[0])
}

// 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.
func (o PacketAuthenticatorOption) Authenticator() []byte {
return o.OptData[1:]
}
73 changes: 0 additions & 73 deletions pkg/slayers/extn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,76 +541,3 @@ func prepRawPacketWithExtn(t *testing.T, extns ...slayers.L4ProtocolType) []byte

return buf.Bytes()
}

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 +
// | |
// + +
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
var rawE2EOptAuth = append(
[]byte{
0x11, 0x05, 0x01, 0x01,
0x0, 0x2, 0x11, 0x0,
},
optAuthMAC...,
)

func TestOptAuthenticatorSerialize(t *testing.T) {
optAuth := slayers.NewPacketAuthenticatorOption(slayers.PacketAuthCMAC, optAuthMAC)

e2e := slayers.EndToEndExtn{}
e2e.NextHdr = slayers.L4UDP
e2e.Options = []*slayers.EndToEndOption{optAuth.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.ParsePacketAuthenticatorOption(optAuth)
require.NoError(t, err, "ParsePacketAuthenticatorOption")
assert.Equal(t, slayers.PacketAuthCMAC, auth.Algorithm(), "Algorithm Type")
assert.Equal(t, optAuthMAC, auth.Authenticator(), "Authenticator data (MAC)")
}

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.ParsePacketAuthenticatorOption(optAuth)
require.Error(t, err, "ParsePacketAuthenticatorOption should fail")
}
Loading

0 comments on commit 944972e

Please sign in to comment.