| // 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 { |
| 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) |
| } |