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.has_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)