303 lines
8.2 KiB
Go
303 lines
8.2 KiB
Go
|
// Copyright 2012 Google, Inc. All rights reserved.
|
||
|
//
|
||
|
// Use of this source code is governed by a BSD-style license
|
||
|
// that can be found in the LICENSE file in the root of the source
|
||
|
// tree.
|
||
|
|
||
|
package layers
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"fmt"
|
||
|
"github.com/google/gopacket"
|
||
|
)
|
||
|
|
||
|
// EAPOL defines an EAP over LAN (802.1x) layer.
|
||
|
type EAPOL struct {
|
||
|
BaseLayer
|
||
|
Version uint8
|
||
|
Type EAPOLType
|
||
|
Length uint16
|
||
|
}
|
||
|
|
||
|
// LayerType returns LayerTypeEAPOL.
|
||
|
func (e *EAPOL) LayerType() gopacket.LayerType { return LayerTypeEAPOL }
|
||
|
|
||
|
// DecodeFromBytes decodes the given bytes into this layer.
|
||
|
func (e *EAPOL) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
|
||
|
if len(data) < 4 {
|
||
|
df.SetTruncated()
|
||
|
return fmt.Errorf("EAPOL length %d too short", len(data))
|
||
|
}
|
||
|
e.Version = data[0]
|
||
|
e.Type = EAPOLType(data[1])
|
||
|
e.Length = binary.BigEndian.Uint16(data[2:4])
|
||
|
e.BaseLayer = BaseLayer{data[:4], data[4:]}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// SerializeTo writes the serialized form of this layer into the
|
||
|
// SerializationBuffer, implementing gopacket.SerializableLayer
|
||
|
func (e *EAPOL) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
|
||
|
bytes, _ := b.PrependBytes(4)
|
||
|
bytes[0] = e.Version
|
||
|
bytes[1] = byte(e.Type)
|
||
|
binary.BigEndian.PutUint16(bytes[2:], e.Length)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// CanDecode returns the set of layer types that this DecodingLayer can decode.
|
||
|
func (e *EAPOL) CanDecode() gopacket.LayerClass {
|
||
|
return LayerTypeEAPOL
|
||
|
}
|
||
|
|
||
|
// NextLayerType returns the layer type contained by this DecodingLayer.
|
||
|
func (e *EAPOL) NextLayerType() gopacket.LayerType {
|
||
|
return e.Type.LayerType()
|
||
|
}
|
||
|
|
||
|
func decodeEAPOL(data []byte, p gopacket.PacketBuilder) error {
|
||
|
e := &EAPOL{}
|
||
|
return decodingLayerDecoder(e, data, p)
|
||
|
}
|
||
|
|
||
|
// EAPOLKeyDescriptorType is an enumeration of key descriptor types
|
||
|
// as specified by 802.1x in the EAPOL-Key frame
|
||
|
type EAPOLKeyDescriptorType uint8
|
||
|
|
||
|
// Enumeration of EAPOLKeyDescriptorType
|
||
|
const (
|
||
|
EAPOLKeyDescriptorTypeRC4 EAPOLKeyDescriptorType = 1
|
||
|
EAPOLKeyDescriptorTypeDot11 EAPOLKeyDescriptorType = 2
|
||
|
EAPOLKeyDescriptorTypeWPA EAPOLKeyDescriptorType = 254
|
||
|
)
|
||
|
|
||
|
func (kdt EAPOLKeyDescriptorType) String() string {
|
||
|
switch kdt {
|
||
|
case EAPOLKeyDescriptorTypeRC4:
|
||
|
return "RC4"
|
||
|
case EAPOLKeyDescriptorTypeDot11:
|
||
|
return "802.11"
|
||
|
case EAPOLKeyDescriptorTypeWPA:
|
||
|
return "WPA"
|
||
|
default:
|
||
|
return fmt.Sprintf("unknown descriptor type %d", kdt)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// EAPOLKeyDescriptorVersion is an enumeration of versions specifying the
|
||
|
// encryption algorithm for the key data and the authentication for the
|
||
|
// message integrity code (MIC)
|
||
|
type EAPOLKeyDescriptorVersion uint8
|
||
|
|
||
|
// Enumeration of EAPOLKeyDescriptorVersion
|
||
|
const (
|
||
|
EAPOLKeyDescriptorVersionOther EAPOLKeyDescriptorVersion = 0
|
||
|
EAPOLKeyDescriptorVersionRC4HMACMD5 EAPOLKeyDescriptorVersion = 1
|
||
|
EAPOLKeyDescriptorVersionAESHMACSHA1 EAPOLKeyDescriptorVersion = 2
|
||
|
EAPOLKeyDescriptorVersionAES128CMAC EAPOLKeyDescriptorVersion = 3
|
||
|
)
|
||
|
|
||
|
func (v EAPOLKeyDescriptorVersion) String() string {
|
||
|
switch v {
|
||
|
case EAPOLKeyDescriptorVersionOther:
|
||
|
return "Other"
|
||
|
case EAPOLKeyDescriptorVersionRC4HMACMD5:
|
||
|
return "RC4-HMAC-MD5"
|
||
|
case EAPOLKeyDescriptorVersionAESHMACSHA1:
|
||
|
return "AES-HMAC-SHA1-128"
|
||
|
case EAPOLKeyDescriptorVersionAES128CMAC:
|
||
|
return "AES-128-CMAC"
|
||
|
default:
|
||
|
return fmt.Sprintf("unknown version %d", v)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// EAPOLKeyType is an enumeration of key derivation types describing
|
||
|
// the purpose of the keys being derived.
|
||
|
type EAPOLKeyType uint8
|
||
|
|
||
|
// Enumeration of EAPOLKeyType
|
||
|
const (
|
||
|
EAPOLKeyTypeGroupSMK EAPOLKeyType = 0
|
||
|
EAPOLKeyTypePairwise EAPOLKeyType = 1
|
||
|
)
|
||
|
|
||
|
func (kt EAPOLKeyType) String() string {
|
||
|
switch kt {
|
||
|
case EAPOLKeyTypeGroupSMK:
|
||
|
return "Group/SMK"
|
||
|
case EAPOLKeyTypePairwise:
|
||
|
return "Pairwise"
|
||
|
default:
|
||
|
return fmt.Sprintf("unknown key type %d", kt)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// EAPOLKey defines an EAPOL-Key frame for 802.1x authentication
|
||
|
type EAPOLKey struct {
|
||
|
BaseLayer
|
||
|
KeyDescriptorType EAPOLKeyDescriptorType
|
||
|
KeyDescriptorVersion EAPOLKeyDescriptorVersion
|
||
|
KeyType EAPOLKeyType
|
||
|
KeyIndex uint8
|
||
|
Install bool
|
||
|
KeyACK bool
|
||
|
KeyMIC bool
|
||
|
Secure bool
|
||
|
MICError bool
|
||
|
Request bool
|
||
|
HasEncryptedKeyData bool
|
||
|
SMKMessage bool
|
||
|
KeyLength uint16
|
||
|
ReplayCounter uint64
|
||
|
Nonce []byte
|
||
|
IV []byte
|
||
|
RSC uint64
|
||
|
ID uint64
|
||
|
MIC []byte
|
||
|
KeyDataLength uint16
|
||
|
EncryptedKeyData []byte
|
||
|
}
|
||
|
|
||
|
// LayerType returns LayerTypeEAPOLKey.
|
||
|
func (ek *EAPOLKey) LayerType() gopacket.LayerType {
|
||
|
return LayerTypeEAPOLKey
|
||
|
}
|
||
|
|
||
|
// CanDecode returns the set of layer types that this DecodingLayer can decode.
|
||
|
func (ek *EAPOLKey) CanDecode() gopacket.LayerType {
|
||
|
return LayerTypeEAPOLKey
|
||
|
}
|
||
|
|
||
|
// NextLayerType returns layers.LayerTypeDot11InformationElement if the key
|
||
|
// data exists and is unencrypted, otherwise it does not expect a next layer.
|
||
|
func (ek *EAPOLKey) NextLayerType() gopacket.LayerType {
|
||
|
if !ek.HasEncryptedKeyData && ek.KeyDataLength > 0 {
|
||
|
return LayerTypeDot11InformationElement
|
||
|
}
|
||
|
return gopacket.LayerTypePayload
|
||
|
}
|
||
|
|
||
|
const eapolKeyFrameLen = 95
|
||
|
|
||
|
// DecodeFromBytes decodes the given bytes into this layer.
|
||
|
func (ek *EAPOLKey) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error {
|
||
|
if len(data) < eapolKeyFrameLen {
|
||
|
df.SetTruncated()
|
||
|
return fmt.Errorf("EAPOLKey length %v too short, %v required",
|
||
|
len(data), eapolKeyFrameLen)
|
||
|
}
|
||
|
|
||
|
ek.KeyDescriptorType = EAPOLKeyDescriptorType(data[0])
|
||
|
|
||
|
info := binary.BigEndian.Uint16(data[1:3])
|
||
|
ek.KeyDescriptorVersion = EAPOLKeyDescriptorVersion(info & 0x0007)
|
||
|
ek.KeyType = EAPOLKeyType((info & 0x0008) >> 3)
|
||
|
ek.KeyIndex = uint8((info & 0x0030) >> 4)
|
||
|
ek.Install = (info & 0x0040) != 0
|
||
|
ek.KeyACK = (info & 0x0080) != 0
|
||
|
ek.KeyMIC = (info & 0x0100) != 0
|
||
|
ek.Secure = (info & 0x0200) != 0
|
||
|
ek.MICError = (info & 0x0400) != 0
|
||
|
ek.Request = (info & 0x0800) != 0
|
||
|
ek.HasEncryptedKeyData = (info & 0x1000) != 0
|
||
|
ek.SMKMessage = (info & 0x2000) != 0
|
||
|
|
||
|
ek.KeyLength = binary.BigEndian.Uint16(data[3:5])
|
||
|
ek.ReplayCounter = binary.BigEndian.Uint64(data[5:13])
|
||
|
|
||
|
ek.Nonce = data[13:45]
|
||
|
ek.IV = data[45:61]
|
||
|
ek.RSC = binary.BigEndian.Uint64(data[61:69])
|
||
|
ek.ID = binary.BigEndian.Uint64(data[69:77])
|
||
|
ek.MIC = data[77:93]
|
||
|
|
||
|
ek.KeyDataLength = binary.BigEndian.Uint16(data[93:95])
|
||
|
|
||
|
totalLength := eapolKeyFrameLen + int(ek.KeyDataLength)
|
||
|
if len(data) < totalLength {
|
||
|
df.SetTruncated()
|
||
|
return fmt.Errorf("EAPOLKey data length %d too short, %d required",
|
||
|
len(data)-eapolKeyFrameLen, ek.KeyDataLength)
|
||
|
}
|
||
|
|
||
|
if ek.HasEncryptedKeyData {
|
||
|
ek.EncryptedKeyData = data[eapolKeyFrameLen:totalLength]
|
||
|
ek.BaseLayer = BaseLayer{
|
||
|
Contents: data[:totalLength],
|
||
|
Payload: data[totalLength:],
|
||
|
}
|
||
|
} else {
|
||
|
ek.BaseLayer = BaseLayer{
|
||
|
Contents: data[:eapolKeyFrameLen],
|
||
|
Payload: data[eapolKeyFrameLen:],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// SerializeTo writes the serialized form of this layer into the
|
||
|
// SerializationBuffer, implementing gopacket.SerializableLayer.
|
||
|
// See the docs for gopacket.SerializableLayer for more info.
|
||
|
func (ek *EAPOLKey) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
|
||
|
buf, err := b.PrependBytes(eapolKeyFrameLen + len(ek.EncryptedKeyData))
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
buf[0] = byte(ek.KeyDescriptorType)
|
||
|
|
||
|
var info uint16
|
||
|
info |= uint16(ek.KeyDescriptorVersion)
|
||
|
info |= uint16(ek.KeyType) << 3
|
||
|
info |= uint16(ek.KeyIndex) << 4
|
||
|
if ek.Install {
|
||
|
info |= 0x0040
|
||
|
}
|
||
|
if ek.KeyACK {
|
||
|
info |= 0x0080
|
||
|
}
|
||
|
if ek.KeyMIC {
|
||
|
info |= 0x0100
|
||
|
}
|
||
|
if ek.Secure {
|
||
|
info |= 0x0200
|
||
|
}
|
||
|
if ek.MICError {
|
||
|
info |= 0x0400
|
||
|
}
|
||
|
if ek.Request {
|
||
|
info |= 0x0800
|
||
|
}
|
||
|
if ek.HasEncryptedKeyData {
|
||
|
info |= 0x1000
|
||
|
}
|
||
|
if ek.SMKMessage {
|
||
|
info |= 0x2000
|
||
|
}
|
||
|
binary.BigEndian.PutUint16(buf[1:3], info)
|
||
|
|
||
|
binary.BigEndian.PutUint16(buf[3:5], ek.KeyLength)
|
||
|
binary.BigEndian.PutUint64(buf[5:13], ek.ReplayCounter)
|
||
|
|
||
|
copy(buf[13:45], ek.Nonce)
|
||
|
copy(buf[45:61], ek.IV)
|
||
|
binary.BigEndian.PutUint64(buf[61:69], ek.RSC)
|
||
|
binary.BigEndian.PutUint64(buf[69:77], ek.ID)
|
||
|
copy(buf[77:93], ek.MIC)
|
||
|
|
||
|
binary.BigEndian.PutUint16(buf[93:95], ek.KeyDataLength)
|
||
|
if len(ek.EncryptedKeyData) > 0 {
|
||
|
copy(buf[95:95+len(ek.EncryptedKeyData)], ek.EncryptedKeyData)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func decodeEAPOLKey(data []byte, p gopacket.PacketBuilder) error {
|
||
|
ek := &EAPOLKey{}
|
||
|
return decodingLayerDecoder(ek, data, p)
|
||
|
}
|