1# SPDX-License-Identifier: GPL-2.0-only 2# This file is part of Scapy 3# See https://scapy.net/ for more information 4# Copyright (C) Philippe Biondi <phil@secdev.org> 5 6""" 7Extensible Authentication Protocol (EAP) 8""" 9 10 11import struct 12 13from scapy.fields import ( 14 BitEnumField, 15 BitField, 16 ByteEnumField, 17 ByteField, 18 ConditionalField, 19 FieldLenField, 20 FieldListField, 21 IntField, 22 LenField, 23 LongField, 24 PacketField, 25 PacketListField, 26 PadField, 27 ShortField, 28 StrLenField, 29 XByteField, 30 XIntField, 31 XStrField, 32 XStrFixedLenField, 33 XStrLenField, 34) 35from scapy.packet import ( 36 Packet, 37 Padding, 38 bind_bottom_up, 39 bind_layers, 40 bind_top_down, 41) 42from scapy.layers.l2 import SourceMACField, Ether, CookedLinux, GRE, SNAP 43from scapy.config import conf 44from scapy.compat import orb, chb 45 46# 47# EAPOL 48# 49 50######################################################################### 51# 52# EAPOL protocol version 53# IEEE Std 802.1X-2010 - Section 11.3.1 54######################################################################### 55# 56 57eapol_versions = { 58 0x1: "802.1X-2001", 59 0x2: "802.1X-2004", 60 0x3: "802.1X-2010", 61} 62 63######################################################################### 64# 65# EAPOL Packet Types 66# IEEE Std 802.1X-2010 - Table 11.3 67######################################################################### 68# 69 70eapol_types = { 71 0x0: "EAP-Packet", # "EAPOL-EAP" in 801.1X-2010 72 0x1: "EAPOL-Start", 73 0x2: "EAPOL-Logoff", 74 0x3: "EAPOL-Key", 75 0x4: "EAPOL-Encapsulated-ASF-Alert", 76 0x5: "EAPOL-MKA", 77 0x6: "EAPOL-Announcement (Generic)", 78 0x7: "EAPOL-Announcement (Specific)", 79 0x8: "EAPOL-Announcement-Req" 80} 81 82 83class EAPOL(Packet): 84 """ 85 EAPOL - IEEE Std 802.1X-2010 86 """ 87 88 name = "EAPOL" 89 fields_desc = [ 90 ByteEnumField("version", 1, eapol_versions), 91 ByteEnumField("type", 0, eapol_types), 92 LenField("len", None, "H") 93 ] 94 95 EAP_PACKET = 0 96 START = 1 97 LOGOFF = 2 98 KEY = 3 99 ASF = 4 100 101 def extract_padding(self, s): 102 tmp_len = self.len 103 return s[:tmp_len], s[tmp_len:] 104 105 def hashret(self): 106 return chb(self.type) + self.payload.hashret() 107 108 def answers(self, other): 109 if isinstance(other, EAPOL): 110 if ((self.type == self.EAP_PACKET) and 111 (other.type == self.EAP_PACKET)): 112 return self.payload.answers(other.payload) 113 return 0 114 115 def mysummary(self): 116 return self.sprintf("EAPOL %EAPOL.type%") 117 118 119# 120# EAP 121# 122 123 124######################################################################### 125# 126# EAP methods types 127# http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-4 128######################################################################### 129# 130 131eap_types = { 132 0: "Reserved", 133 1: "Identity", 134 2: "Notification", 135 3: "Legacy Nak", 136 4: "MD5-Challenge", 137 5: "One-Time Password (OTP)", 138 6: "Generic Token Card (GTC)", 139 7: "Allocated - RFC3748", 140 8: "Allocated - RFC3748", 141 9: "RSA Public Key Authentication", 142 10: "DSS Unilateral", 143 11: "KEA", 144 12: "KEA-VALIDATE", 145 13: "EAP-TLS", 146 14: "Defender Token (AXENT)", 147 15: "RSA Security SecurID EAP", 148 16: "Arcot Systems EAP", 149 17: "EAP-Cisco Wireless", 150 18: "GSM Subscriber Identity Modules (EAP-SIM)", 151 19: "SRP-SHA1", 152 20: "Unassigned", 153 21: "EAP-TTLS", 154 22: "Remote Access Service", 155 23: "EAP-AKA Authentication", 156 24: "EAP-3Com Wireless", 157 25: "PEAP", 158 26: "MS-EAP-Authentication", 159 27: "Mutual Authentication w/Key Exchange (MAKE)", 160 28: "CRYPTOCard", 161 29: "EAP-MSCHAP-V2", 162 30: "DynamID", 163 31: "Rob EAP", 164 32: "Protected One-Time Password", 165 33: "MS-Authentication-TLV", 166 34: "SentriNET", 167 35: "EAP-Actiontec Wireless", 168 36: "Cogent Systems Biometrics Authentication EAP", 169 37: "AirFortress EAP", 170 38: "EAP-HTTP Digest", 171 39: "SecureSuite EAP", 172 40: "DeviceConnect EAP", 173 41: "EAP-SPEKE", 174 42: "EAP-MOBAC", 175 43: "EAP-FAST", 176 44: "ZoneLabs EAP (ZLXEAP)", 177 45: "EAP-Link", 178 46: "EAP-PAX", 179 47: "EAP-PSK", 180 48: "EAP-SAKE", 181 49: "EAP-IKEv2", 182 50: "EAP-AKA", 183 51: "EAP-GPSK", 184 52: "EAP-pwd", 185 53: "EAP-EKE Version 1", 186 54: "EAP Method Type for PT-EAP", 187 55: "TEAP", 188 254: "Reserved for the Expanded Type", 189 255: "Experimental", 190} 191 192 193######################################################################### 194# 195# EAP codes 196# http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-1 197######################################################################### 198# 199 200eap_codes = { 201 1: "Request", 202 2: "Response", 203 3: "Success", 204 4: "Failure", 205 5: "Initiate", 206 6: "Finish" 207} 208 209 210class EAP(Packet): 211 """ 212 RFC 3748 - Extensible Authentication Protocol (EAP) 213 """ 214 215 name = "EAP" 216 fields_desc = [ 217 ByteEnumField("code", 4, eap_codes), 218 ByteField("id", 0), 219 ShortField("len", None), 220 ConditionalField(ByteEnumField("type", 0, eap_types), 221 lambda pkt:pkt.code not in [ 222 EAP.SUCCESS, EAP.FAILURE]), 223 ConditionalField( 224 FieldListField("desired_auth_types", [], 225 ByteEnumField("auth_type", 0, eap_types), 226 length_from=lambda pkt: pkt.len - 4), 227 lambda pkt:pkt.code == EAP.RESPONSE and pkt.type == 3), 228 ConditionalField( 229 StrLenField("identity", '', length_from=lambda pkt: pkt.len - 5), 230 lambda pkt: pkt.code == EAP.RESPONSE and hasattr(pkt, 'type') and pkt.type == 1), # noqa: E501 231 ConditionalField( 232 StrLenField("message", '', length_from=lambda pkt: pkt.len - 5), 233 lambda pkt: pkt.code == EAP.REQUEST and hasattr(pkt, 'type') and pkt.type == 1) # noqa: E501 234 ] 235 236 ######################################################################### 237 # 238 # EAP codes 239 # http://www.iana.org/assignments/eap-numbers/eap-numbers.xhtml#eap-numbers-1 240 ######################################################################### 241 # 242 243 REQUEST = 1 244 RESPONSE = 2 245 SUCCESS = 3 246 FAILURE = 4 247 INITIATE = 5 248 FINISH = 6 249 250 registered_methods = {} 251 252 @classmethod 253 def register_variant(cls): 254 cls.registered_methods[cls.type.default] = cls 255 256 @classmethod 257 def dispatch_hook(cls, _pkt=None, *args, **kargs): 258 if _pkt: 259 c = orb(_pkt[0]) 260 if c in [1, 2] and len(_pkt) >= 5: 261 t = orb(_pkt[4]) 262 return cls.registered_methods.get(t, cls) 263 return cls 264 265 def answers(self, other): 266 if isinstance(other, EAP): 267 if self.code == self.REQUEST: 268 return 0 269 elif self.code == self.RESPONSE: 270 if ((other.code == self.REQUEST) and 271 (other.type == self.type)): 272 return 1 273 elif other.code == self.RESPONSE: 274 return 1 275 return 0 276 277 def mysummary(self): 278 summary_str = "EAP %{eap_class}.code% %{eap_class}.type%".format( 279 eap_class=self.__class__.__name__ 280 ) 281 if self.type == 1 and self.code == EAP.RESPONSE: 282 summary_str += " %{eap_class}.identity%".format( 283 eap_class=self.__class__.__name__ 284 ) 285 return self.sprintf(summary_str) 286 287 def post_build(self, p, pay): 288 if self.len is None: 289 tmp_len = len(p) + len(pay) 290 tmp_p = p[:2] + chb((tmp_len >> 8) & 0xff) + chb(tmp_len & 0xff) 291 p = tmp_p + p[4:] 292 return p + pay 293 294 def guess_payload_class(self, _): 295 return Padding 296 297 298class EAP_MD5(EAP): 299 """ 300 RFC 3748 - "Extensible Authentication Protocol (EAP)" 301 """ 302 303 name = "EAP-MD5" 304 match_subclass = True 305 fields_desc = [ 306 ByteEnumField("code", 1, eap_codes), 307 ByteField("id", 0), 308 FieldLenField("len", None, fmt="H", length_of="optional_name", 309 adjust=lambda p, x: x + 6 + (p.value_size or 0)), 310 ByteEnumField("type", 4, eap_types), 311 FieldLenField("value_size", None, fmt="B", length_of="value"), 312 XStrLenField("value", '', length_from=lambda p: p.value_size), 313 XStrLenField("optional_name", '', length_from=lambda p: 0 if p.len is None or p.value_size is None else (p.len - p.value_size - 6)) # noqa: E501 314 ] 315 316 317class EAP_TLS(EAP): 318 """ 319 RFC 5216 - "The EAP-TLS Authentication Protocol" 320 """ 321 322 name = "EAP-TLS" 323 match_subclass = True 324 fields_desc = [ 325 ByteEnumField("code", 1, eap_codes), 326 ByteField("id", 0), 327 FieldLenField("len", None, fmt="H", length_of="tls_data", 328 adjust=lambda p, x: x + 10 if p.L == 1 else x + 6), 329 ByteEnumField("type", 13, eap_types), 330 BitField('L', 0, 1), 331 BitField('M', 0, 1), 332 BitField('S', 0, 1), 333 BitField('reserved', 0, 5), 334 ConditionalField(IntField('tls_message_len', 0), lambda pkt: pkt.L == 1), # noqa: E501 335 XStrLenField('tls_data', '', length_from=lambda pkt: 0 if pkt.len is None else pkt.len - (6 + 4 * pkt.L)) # noqa: E501 336 ] 337 338 339class EAP_TTLS(EAP): 340 """ 341 RFC 5281 - "Extensible Authentication Protocol Tunneled Transport Layer 342 Security Authenticated Protocol Version 0 (EAP-TTLSv0)" 343 """ 344 345 name = "EAP-TTLS" 346 match_subclass = True 347 fields_desc = [ 348 ByteEnumField("code", 1, eap_codes), 349 ByteField("id", 0), 350 FieldLenField("len", None, fmt="H", length_of="data", 351 adjust=lambda p, x: x + 10 if p.L == 1 else x + 6), 352 ByteEnumField("type", 21, eap_types), 353 BitField("L", 0, 1), 354 BitField("M", 0, 1), 355 BitField("S", 0, 1), 356 BitField("reserved", 0, 2), 357 BitField("version", 0, 3), 358 ConditionalField(IntField("message_len", 0), lambda pkt: pkt.L == 1), 359 XStrLenField("data", "", length_from=lambda pkt: 0 if pkt.len is None else pkt.len - (6 + 4 * pkt.L)) # noqa: E501 360 ] 361 362 363class EAP_PEAP(EAP): 364 """ 365 draft-josefsson-pppext-eap-tls-eap-05.txt - "Protected EAP Protocol (PEAP)" 366 """ 367 368 name = "PEAP" 369 match_subclass = True 370 fields_desc = [ 371 ByteEnumField("code", 1, eap_codes), 372 ByteField("id", 0), 373 FieldLenField("len", None, fmt="H", length_of="tls_data", 374 adjust=lambda p, x: x + 10 if p.L == 1 else x + 6), 375 ByteEnumField("type", 25, eap_types), 376 BitField("L", 0, 1), 377 BitField("M", 0, 1), 378 BitField("S", 0, 1), 379 BitField("reserved", 0, 3), 380 BitField("version", 1, 2), 381 ConditionalField(IntField("tls_message_len", 0), lambda pkt: pkt.L == 1), # noqa: E501 382 XStrLenField("tls_data", "", length_from=lambda pkt: 0 if pkt.len is None else pkt.len - (6 + 4 * pkt.L)) # noqa: E501 383 ] 384 385 386class EAP_FAST(EAP): 387 """ 388 RFC 4851 - "The Flexible Authentication via Secure Tunneling 389 Extensible Authentication Protocol Method (EAP-FAST)" 390 """ 391 392 name = "EAP-FAST" 393 match_subclass = True 394 fields_desc = [ 395 ByteEnumField("code", 1, eap_codes), 396 ByteField("id", 0), 397 FieldLenField("len", None, fmt="H", length_of="data", 398 adjust=lambda p, x: x + 10 if p.L == 1 else x + 6), 399 ByteEnumField("type", 43, eap_types), 400 BitField('L', 0, 1), 401 BitField('M', 0, 1), 402 BitField('S', 0, 1), 403 BitField('reserved', 0, 2), 404 BitField('version', 0, 3), 405 ConditionalField(IntField('message_len', 0), lambda pkt: pkt.L == 1), 406 XStrLenField('data', '', length_from=lambda pkt: 0 if pkt.len is None else pkt.len - (6 + 4 * pkt.L)) # noqa: E501 407 ] 408 409 410class LEAP(EAP): 411 """ 412 Cisco LEAP (Lightweight EAP) 413 https://freeradius.org/rfc/leap.txt 414 """ 415 416 name = "Cisco LEAP" 417 match_subclass = True 418 fields_desc = [ 419 ByteEnumField("code", 1, eap_codes), 420 ByteField("id", 0), 421 ShortField("len", None), 422 ByteEnumField("type", 17, eap_types), 423 ByteField('version', 1), 424 XByteField('unused', 0), 425 FieldLenField("count", None, "challenge_response", "B", adjust=lambda p, x: len(p.challenge_response)), # noqa: E501 426 XStrLenField("challenge_response", "", length_from=lambda p: 0 or p.count), # noqa: E501 427 StrLenField("username", "", length_from=lambda p: p.len - (8 + (0 or p.count))) # noqa: E501 428 ] 429 430 431############################################################################# 432# IEEE 802.1X-2010 - EAPOL-Key 433############################################################################# 434 435# sect 11.9 of 802.1X-2010 436# AND sect 12.7.2 of 802.11-2016 437 438 439class EAPOL_KEY(Packet): 440 name = "EAPOL_KEY" 441 deprecated_fields = { 442 "key": ("key_data", "2.6.0"), 443 "len": ("key_length", "2.6.0"), 444 } 445 fields_desc = [ 446 ByteEnumField("key_descriptor_type", 1, {1: "RC4", 2: "RSN"}), 447 # Key Information 448 BitField("res2", 0, 2), 449 BitField("smk_message", 0, 1), 450 BitField("encrypted_key_data", 0, 1), 451 BitField("request", 0, 1), 452 BitField("error", 0, 1), 453 BitField("secure", 0, 1), 454 BitField("has_key_mic", 1, 1), 455 BitField("key_ack", 0, 1), 456 BitField("install", 0, 1), 457 BitField("res", 0, 2), 458 BitEnumField("key_type", 0, 1, {0: "Group/SMK", 1: "Pairwise"}), 459 BitEnumField("key_descriptor_type_version", 0, 3, { 460 1: "HMAC-MD5+ARC4", 461 2: "HMAC-SHA1-128+AES-128", 462 3: "AES-128-CMAC+AES-128", 463 }), 464 # 465 LenField("key_length", None, "H"), 466 LongField("key_replay_counter", 0), 467 XStrFixedLenField("key_nonce", "", 32), 468 XStrFixedLenField("key_iv", "", 16), 469 XStrFixedLenField("key_rsc", "", 8), 470 XStrFixedLenField("key_id", "", 8), 471 XStrFixedLenField("key_mic", "", 16), # XXX size can be 24 472 FieldLenField("key_data_length", None, length_of="key_data"), 473 XStrLenField("key_data", "", 474 length_from=lambda pkt: pkt.key_data_length) 475 ] 476 477 def extract_padding(self, s): 478 return s[:self.key_length], s[self.key_length:] 479 480 def hashret(self): 481 return struct.pack("!B", self.type) + self.payload.hashret() 482 483 def answers(self, other): 484 if isinstance(other, EAPOL_KEY) and \ 485 other.descriptor_type == self.descriptor_type: 486 return 1 487 return 0 488 489 def guess_key_number(self): 490 """ 491 Determines 4-way handshake key number 492 493 :return: key number (1-4), or 0 if it cannot be determined 494 """ 495 if self.key_type == 1: 496 if self.key_ack == 1: 497 if self.key_mic == 0: 498 return 1 499 if self.install == 1: 500 return 3 501 else: 502 if self.secure == 0: 503 return 2 504 return 4 505 return 0 506 507 508############################################################################# 509# IEEE 802.1X-2010 - MACsec Key Agreement (MKA) protocol 510############################################################################# 511 512######################################################################### 513# 514# IEEE 802.1X-2010 standard 515# Section 11.11.1 516######################################################################### 517# 518 519_parameter_set_types = { 520 1: "Live Peer List", 521 2: "Potential Peer List", 522 3: "MACsec SAK Use", 523 4: "Distributed SAK", 524 5: "Distributed CAK", 525 6: "KMD", 526 7: "Announcement", 527 255: "ICV Indicator" 528} 529 530 531# Used by MKAParamSet::dispatch_hook() to instantiate the appropriate class 532_param_set_cls = { 533 1: "MKALivePeerListParamSet", 534 2: "MKAPotentialPeerListParamSet", 535 3: "MKASAKUseParamSet", 536 4: "MKADistributedSAKParamSet", 537 255: "MKAICVSet", 538} 539 540 541class MACsecSCI(Packet): 542 """ 543 Secure Channel Identifier. 544 """ 545 546 ######################################################################### 547 # 548 # IEEE 802.1AE-2006 standard 549 # Section 9.9 550 ######################################################################### 551 # 552 553 name = "SCI" 554 fields_desc = [ 555 SourceMACField("system_identifier"), 556 ShortField("port_identifier", 0) 557 ] 558 559 def extract_padding(self, s): 560 return "", s 561 562 563class MKAParamSet(Packet): 564 """ 565 Class from which every parameter set class inherits (except 566 MKABasicParamSet, which has no "Parameter set type" field, and must 567 come first in the list of parameter sets). 568 """ 569 570 MACSEC_DEFAULT_ICV_LEN = 16 571 EAPOL_MKA_DEFAULT_KEY_WRAP_LEN = 24 572 573 @classmethod 574 def dispatch_hook(cls, _pkt=None, *args, **kargs): 575 """ 576 Returns the right parameter set class. 577 """ 578 579 cls = conf.raw_layer 580 if _pkt is not None: 581 ptype = orb(_pkt[0]) 582 return globals().get(_param_set_cls.get(ptype), conf.raw_layer) 583 584 return cls 585 586 587class MKABasicParamSet(Packet): 588 """ 589 Basic Parameter Set (802.1X-2010, section 11.11). 590 """ 591 592 ######################################################################### 593 # 594 # IEEE 802.1X-2010 standard 595 # Section 11.11 596 ######################################################################### 597 # 598 599 name = "Basic Parameter Set" 600 fields_desc = [ 601 ByteField("mka_version_id", 0), 602 ByteField("key_server_priority", 0), 603 BitField("key_server", 0, 1), 604 BitField("macsec_desired", 0, 1), 605 BitField("macsec_capability", 0, 2), 606 BitField("param_set_body_len", 0, 12), 607 PacketField("SCI", MACsecSCI(), MACsecSCI), 608 XStrFixedLenField("actor_member_id", "", length=12), 609 XIntField("actor_message_number", 0), 610 XIntField("algorithm_agility", 0), 611 PadField( 612 XStrLenField( 613 "cak_name", 614 "", 615 length_from=lambda pkt: (pkt.param_set_body_len - 28) 616 ), 617 4, 618 padwith=b"\x00" 619 ) 620 ] 621 622 def extract_padding(self, s): 623 return "", s 624 625 626class MKAPeerListTuple(Packet): 627 """ 628 Live / Potential Peer List parameter sets tuples (802.1X-2010, section 11.11). # noqa: E501 629 """ 630 631 name = "Peer List Tuple" 632 fields_desc = [ 633 XStrFixedLenField("member_id", "", length=12), 634 XStrFixedLenField("message_number", "", length=4), 635 ] 636 637 638class MKALivePeerListParamSet(MKAParamSet): 639 """ 640 Live Peer List parameter sets (802.1X-2010, section 11.11). 641 """ 642 643 ######################################################################### 644 # 645 # IEEE 802.1X-2010 standard 646 # Section 11.11 647 ######################################################################### 648 # 649 650 name = "Live Peer List Parameter Set" 651 fields_desc = [ 652 PadField( 653 ByteEnumField( 654 "param_set_type", 655 1, 656 _parameter_set_types 657 ), 658 2, 659 padwith=b"\x00" 660 ), 661 ShortField("param_set_body_len", 0), 662 PacketListField("member_id_message_num", [], MKAPeerListTuple) 663 ] 664 665 666class MKAPotentialPeerListParamSet(MKAParamSet): 667 """ 668 Potential Peer List parameter sets (802.1X-2010, section 11.11). 669 """ 670 671 ######################################################################### 672 # 673 # IEEE 802.1X-2010 standard 674 # Section 11.11 675 ######################################################################### 676 # 677 678 name = "Potential Peer List Parameter Set" 679 fields_desc = [ 680 PadField( 681 ByteEnumField( 682 "param_set_type", 683 2, 684 _parameter_set_types 685 ), 686 2, 687 padwith=b"\x00" 688 ), 689 ShortField("param_set_body_len", 0), 690 PacketListField("member_id_message_num", [], MKAPeerListTuple) 691 ] 692 693 694class MKASAKUseParamSet(MKAParamSet): 695 """ 696 SAK Use Parameter Set (802.1X-2010, section 11.11). 697 """ 698 699 ######################################################################### 700 # 701 # IEEE 802.1X-2010 standard 702 # Section 11.11 703 ######################################################################### 704 # 705 706 name = "SAK Use Parameter Set" 707 fields_desc = [ 708 ByteEnumField("param_set_type", 3, _parameter_set_types), 709 BitField("latest_key_an", 0, 2), 710 BitField("latest_key_tx", 0, 1), 711 BitField("latest_key_rx", 0, 1), 712 BitField("old_key_an", 0, 2), 713 BitField("old_key_tx", 0, 1), 714 BitField("old_key_rx", 0, 1), 715 BitField("plain_tx", 0, 1), 716 BitField("plain_rx", 0, 1), 717 BitField("X", 0, 1), 718 BitField("delay_protect", 0, 1), 719 BitField("param_set_body_len", 0, 12), 720 XStrFixedLenField("latest_key_key_server_member_id", "", length=12), 721 XStrFixedLenField("latest_key_key_number", "", length=4), 722 XStrFixedLenField("latest_key_lowest_acceptable_pn", "", length=4), 723 XStrFixedLenField("old_key_key_server_member_id", "", length=12), 724 XStrFixedLenField("old_key_key_number", "", length=4), 725 XStrFixedLenField("old_key_lowest_acceptable_pn", "", length=4) 726 ] 727 728 729class MKADistributedSAKParamSet(MKAParamSet): 730 """ 731 Distributed SAK parameter set (802.1X-2010, section 11.11). 732 """ 733 734 ######################################################################### 735 # 736 # IEEE 802.1X-2010 standard 737 # Section 11.11 738 ######################################################################### 739 # 740 741 name = "Distributed SAK parameter set" 742 fields_desc = [ 743 ByteEnumField("param_set_type", 4, _parameter_set_types), 744 BitField("distributed_an", 0, 2), 745 BitField("confidentiality_offset", 0, 2), 746 BitField("unused", 0, 4), 747 ShortField("param_set_body_len", 0), 748 XStrFixedLenField("key_number", "", length=4), 749 ConditionalField( 750 XStrFixedLenField("macsec_cipher_suite", "", length=8), 751 lambda pkt: pkt.param_set_body_len > 28 752 ), 753 XStrFixedLenField( 754 "sak_aes_key_wrap", 755 "", 756 length=MKAParamSet.EAPOL_MKA_DEFAULT_KEY_WRAP_LEN 757 ) 758 ] 759 760 761class MKADistributedCAKParamSet(MKAParamSet): 762 """ 763 Distributed CAK Parameter Set (802.1X-2010, section 11.11). 764 """ 765 766 ######################################################################### 767 # 768 # IEEE 802.1X-2010 standard 769 # Section 11.11 770 ######################################################################### 771 # 772 773 name = "Distributed CAK parameter set" 774 fields_desc = [ 775 PadField( 776 ByteEnumField( 777 "param_set_type", 778 5, 779 _parameter_set_types 780 ), 781 2, 782 padwith=b"\x00" 783 ), 784 ShortField("param_set_body_len", 0), 785 XStrFixedLenField( 786 "cak_aes_key_wrap", 787 "", 788 length=MKAParamSet.EAPOL_MKA_DEFAULT_KEY_WRAP_LEN 789 ), 790 XStrField("cak_key_name", "") 791 ] 792 793 794class MKAICVSet(MKAParamSet): 795 """ 796 ICV (802.1X-2010, section 11.11). 797 """ 798 799 ######################################################################### 800 # 801 # IEEE 802.1X-2010 standard 802 # Section 11.11 803 ######################################################################### 804 # 805 806 name = "ICV" 807 fields_desc = [ 808 PadField( 809 ByteEnumField( 810 "param_set_type", 811 255, 812 _parameter_set_types 813 ), 814 2, 815 padwith=b"\x00" 816 ), 817 ShortField("param_set_body_len", 0), 818 XStrFixedLenField("icv", "", length=MKAParamSet.MACSEC_DEFAULT_ICV_LEN) 819 ] 820 821 822class MKAParamSetPacketListField(PacketListField): 823 """ 824 PacketListField that handles the parameter sets. 825 """ 826 827 PARAM_SET_LEN_MASK = 0b0000111111111111 828 829 def m2i(self, pkt, m): 830 return MKAParamSet(m) 831 832 def getfield(self, pkt, s): 833 lst = [] 834 remain = s 835 836 while remain: 837 len_bytes = struct.unpack("!H", remain[2:4])[0] 838 param_set_len = self.__class__.PARAM_SET_LEN_MASK & len_bytes 839 current = remain[:4 + param_set_len] 840 remain = remain[4 + param_set_len:] 841 current_packet = self.m2i(pkt, current) 842 lst.append(current_packet) 843 844 return remain, lst 845 846 847class MKAPDU(Packet): 848 """ 849 MACsec Key Agreement Protocol Data Unit. 850 """ 851 852 ######################################################################### 853 # 854 # IEEE 802.1X-2010 standard 855 # Section 11.11 856 ######################################################################### 857 # 858 859 name = "MKPDU" 860 fields_desc = [ 861 PacketField("basic_param_set", "", MKABasicParamSet), 862 MKAParamSetPacketListField("parameter_sets", [], MKAParamSet), 863 ] 864 865 def extract_padding(self, s): 866 return "", s 867 868 869# Bind EAPOL types 870bind_layers(EAPOL, EAP, type=0) 871bind_layers(EAPOL, EAPOL_KEY, type=3) 872bind_layers(EAPOL, MKAPDU, type=5) 873 874bind_bottom_up(Ether, EAPOL, type=0x888e) 875# the reserved IEEE Std 802.1X PAE address 876bind_top_down(Ether, EAPOL, dst='01:80:c2:00:00:03', type=0x888e) 877bind_layers(CookedLinux, EAPOL, proto=0x888e) 878bind_layers(SNAP, EAPOL, code=0x888e) 879bind_layers(GRE, EAPOL, proto=0x888e) 880