• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) Gabriel Potter
5
6r"""
7Kerberos V5
8
9Implements parts of:
10
11- Kerberos Network Authentication Service (V5): RFC4120
12- Kerberos Version 5 GSS-API: RFC1964, RFC4121
13- Kerberos Pre-Authentication: RFC6113 (FAST)
14- Kerberos Principal Name Canonicalization and Cross-Realm Referrals: RFC6806
15- Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols: RFC3244
16- User to User Kerberos Authentication: draft-ietf-cat-user2user-03
17- Public Key Cryptography Based User-to-User Authentication (PKU2U): draft-zhu-pku2u-09
18- Initial and Pass Through Authentication Using Kerberos V5 (IAKERB):
19  draft-ietf-kitten-iakerb-03
20- Kerberos Protocol Extensions: [MS-KILE]
21- Kerberos Protocol Extensions: Service for User: [MS-SFU]
22
23
24.. note::
25    You will find more complete documentation for this layer over at
26    `Kerberos <https://scapy.readthedocs.io/en/latest/layers/kerberos.html>`_
27
28Example decryption::
29
30    >>> from scapy.libs.rfc3961 import Key, EncryptionType
31    >>> pkt = Ether(hex_bytes("525400695813525400216c2b08004500015da71840008006dc\
32    83c0a87a9cc0a87a11c209005854f6ab2392c25bd650182014b6e00000000001316a8201\
33    2d30820129a103020105a20302010aa3633061304ca103020102a24504433041a0030201\
34    12a23a043848484decb01c9b62a1cabfbc3f2d1ed85aa5e093ba8358a8cea34d4393af93\
35    bf211e274fa58e814878db9f0d7a28d94e7327660db4f3704b3011a10402020080a20904\
36    073005a0030101ffa481b73081b4a00703050040810010a1123010a003020101a1093007\
37    1b0577696e3124a20e1b0c444f4d41494e2e4c4f43414ca321301fa003020102a1183016\
38    1b066b72627467741b0c444f4d41494e2e4c4f43414ca511180f32303337303931333032\
39    343830355aa611180f32303337303931333032343830355aa7060204701cc5d1a8153013\
40    0201120201110201170201180202ff79020103a91d301b3019a003020114a11204105749\
41    4e31202020202020202020202020"))
42    >>> enc = pkt[Kerberos].root.padata[0].padataValue
43    >>> k = Key(enc.etype.val, key=hex_bytes("7fada4e566ae4fb270e2800a23a\
44    e87127a819d42e69b5e22de0ddc63da80096d"))
45    >>> enc.decrypt(k)
46"""
47
48from collections import namedtuple
49from datetime import datetime, timedelta, timezone
50from enum import IntEnum
51
52import os
53import re
54import socket
55import struct
56
57from scapy.error import warning
58import scapy.asn1.mib  # noqa: F401
59from scapy.asn1.ber import BER_id_dec, BER_Decoding_Error
60from scapy.asn1.asn1 import (
61    ASN1_BIT_STRING,
62    ASN1_BOOLEAN,
63    ASN1_Class,
64    ASN1_GENERAL_STRING,
65    ASN1_GENERALIZED_TIME,
66    ASN1_INTEGER,
67    ASN1_STRING,
68    ASN1_Codecs,
69)
70from scapy.asn1fields import (
71    ASN1F_BOOLEAN,
72    ASN1F_CHOICE,
73    ASN1F_FLAGS,
74    ASN1F_GENERAL_STRING,
75    ASN1F_GENERALIZED_TIME,
76    ASN1F_INTEGER,
77    ASN1F_OID,
78    ASN1F_PACKET,
79    ASN1F_SEQUENCE,
80    ASN1F_SEQUENCE_OF,
81    ASN1F_STRING,
82    ASN1F_STRING_PacketField,
83    ASN1F_enum_INTEGER,
84    ASN1F_optional,
85)
86from scapy.asn1packet import ASN1_Packet
87from scapy.automaton import Automaton, ATMT
88from scapy.config import conf
89from scapy.compat import bytes_encode
90from scapy.error import log_runtime
91from scapy.fields import (
92    ConditionalField,
93    FieldLenField,
94    FlagsField,
95    IntEnumField,
96    LEIntEnumField,
97    LenField,
98    LEShortEnumField,
99    LEShortField,
100    LongField,
101    MultipleTypeField,
102    PacketField,
103    PacketLenField,
104    PacketListField,
105    PadField,
106    ShortEnumField,
107    ShortField,
108    StrField,
109    StrFieldUtf16,
110    StrFixedLenEnumField,
111    XByteField,
112    XLEIntField,
113    XLEShortField,
114    XStrFixedLenField,
115    XStrLenField,
116    XStrField,
117)
118from scapy.packet import Packet, bind_bottom_up, bind_top_down, bind_layers
119from scapy.supersocket import StreamSocket
120from scapy.utils import strrot, strxor
121from scapy.volatile import GeneralizedTime, RandNum, RandBin
122
123from scapy.layers.gssapi import (
124    GSSAPI_BLOB,
125    GSS_C_FLAGS,
126    GSS_S_BAD_MECH,
127    GSS_S_COMPLETE,
128    GSS_S_CONTINUE_NEEDED,
129    GSS_S_DEFECTIVE_TOKEN,
130    GSS_S_FAILURE,
131    GssChannelBindings,
132    SSP,
133    _GSSAPI_OIDS,
134    _GSSAPI_SIGNATURE_OIDS,
135)
136from scapy.layers.inet import TCP, UDP
137
138# Typing imports
139from typing import (
140    Optional,
141)
142
143
144# kerberos APPLICATION
145
146
147class ASN1_Class_KRB(ASN1_Class):
148    name = "Kerberos"
149    # APPLICATION + CONSTRUCTED = 0x40 | 0x20
150    Token = 0x60 | 0  # GSSAPI
151    Ticket = 0x60 | 1
152    Authenticator = 0x60 | 2
153    EncTicketPart = 0x60 | 3
154    AS_REQ = 0x60 | 10
155    AS_REP = 0x60 | 11
156    TGS_REQ = 0x60 | 12
157    TGS_REP = 0x60 | 13
158    AP_REQ = 0x60 | 14
159    AP_REP = 0x60 | 15
160    PRIV = 0x60 | 21
161    CRED = 0x60 | 22
162    EncASRepPart = 0x60 | 25
163    EncTGSRepPart = 0x60 | 26
164    EncAPRepPart = 0x60 | 27
165    EncKrbPrivPart = 0x60 | 28
166    EncKrbCredPart = 0x60 | 29
167    ERROR = 0x60 | 30
168
169
170# RFC4120 sect 5.2
171
172
173KerberosString = ASN1F_GENERAL_STRING
174Realm = KerberosString
175Int32 = ASN1F_INTEGER
176UInt32 = ASN1F_INTEGER
177
178_PRINCIPAL_NAME_TYPES = {
179    0: "NT-UNKNOWN",
180    1: "NT-PRINCIPAL",
181    2: "NT-SRV-INST",
182    3: "NT-SRV-HST",
183    4: "NT-SRV-XHST",
184    5: "NT-UID",
185    6: "NT-X500-PRINCIPAL",
186    7: "NT-SMTP-NAME",
187    10: "NT-ENTERPRISE",
188}
189
190
191class PrincipalName(ASN1_Packet):
192    ASN1_codec = ASN1_Codecs.BER
193    ASN1_root = ASN1F_SEQUENCE(
194        ASN1F_enum_INTEGER(
195            "nameType",
196            0,
197            _PRINCIPAL_NAME_TYPES,
198            explicit_tag=0xA0,
199        ),
200        ASN1F_SEQUENCE_OF("nameString", [], KerberosString, explicit_tag=0xA1),
201    )
202
203    @staticmethod
204    def fromUPN(upn: str):
205        user, _ = _parse_upn(upn)
206        return PrincipalName(
207            nameString=[ASN1_GENERAL_STRING(user)],
208            nameType=ASN1_INTEGER(1),  # NT-PRINCIPAL
209        )
210
211    @staticmethod
212    def fromSPN(spn: bytes):
213        spn, _ = _parse_spn(spn)
214        if spn.startswith("krbtgt"):
215            return PrincipalName(
216                nameString=[ASN1_GENERAL_STRING(x) for x in spn.split("/")],
217                nameType=ASN1_INTEGER(2),  # NT-SRV-INST
218            )
219        else:
220            return PrincipalName(
221                nameString=[ASN1_GENERAL_STRING(x) for x in spn.split("/")],
222                nameType=ASN1_INTEGER(3),  # NT-SRV-HST
223            )
224
225
226KerberosTime = ASN1F_GENERALIZED_TIME
227Microseconds = ASN1F_INTEGER
228
229
230# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1
231
232_KRB_E_TYPES = {
233    1: "DES-CBC-CRC",
234    2: "DES-CBC-MD4",
235    3: "DES-CBC-MD5",
236    5: "DES3-CBC-MD5",
237    7: "DES3-CBC-SHA1",
238    9: "DSAWITHSHA1-CMSOID",
239    10: "MD5WITHRSAENCRYPTION-CMSOID",
240    11: "SHA1WITHRSAENCRYPTION-CMSOID",
241    12: "RC2CBC-ENVOID",
242    13: "RSAENCRYPTION-ENVOID",
243    14: "RSAES-OAEP-ENV-OID",
244    15: "DES-EDE3-CBC-ENV-OID",
245    16: "DES3-CBC-SHA1-KD",
246    17: "AES128-CTS-HMAC-SHA1-96",
247    18: "AES256-CTS-HMAC-SHA1-96",
248    19: "AES128-CTS-HMAC-SHA256-128",
249    20: "AES256-CTS-HMAC-SHA384-192",
250    23: "RC4-HMAC",
251    24: "RC4-HMAC-EXP",
252    25: "CAMELLIA128-CTS-CMAC",
253    26: "CAMELLIA256-CTS-CMAC",
254}
255
256# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-2
257
258_KRB_S_TYPES = {
259    1: "CRC32",
260    2: "RSA-MD4",
261    3: "RSA-MD4-DES",
262    4: "DES-MAC",
263    5: "DES-MAC-K",
264    6: "RSA-MD4-DES-K",
265    7: "RSA-MD5",
266    8: "RSA-MD5-DES",
267    9: "RSA-MD5-DES3",
268    10: "SHA1",
269    12: "HMAC-SHA1-DES3-KD",
270    13: "HMAC-SHA1-DES3",
271    14: "SHA1",
272    15: "HMAC-SHA1-96-AES128",
273    16: "HMAC-SHA1-96-AES256",
274    17: "CMAC-CAMELLIA128",
275    18: "CMAC-CAMELLIA256",
276    19: "HMAC-SHA256-128-AES128",
277    20: "HMAC-SHA384-192-AES256",
278    # RFC 4121
279    0x8003: "KRB-AUTHENTICATOR",
280    # [MS-KILE]
281    0xFFFFFF76: "MD5",
282}
283
284
285class EncryptedData(ASN1_Packet):
286    ASN1_codec = ASN1_Codecs.BER
287    ASN1_root = ASN1F_SEQUENCE(
288        ASN1F_enum_INTEGER("etype", 0x17, _KRB_E_TYPES, explicit_tag=0xA0),
289        ASN1F_optional(UInt32("kvno", None, explicit_tag=0xA1)),
290        ASN1F_STRING("cipher", "", explicit_tag=0xA2),
291    )
292
293    def get_usage(self):
294        """
295        Get current key usage number and encrypted class
296        """
297        # RFC 4120 sect 7.5.1
298        if self.underlayer:
299            if isinstance(self.underlayer, PADATA):
300                patype = self.underlayer.padataType
301                if patype == 2:
302                    # AS-REQ PA-ENC-TIMESTAMP padata timestamp
303                    return 1, PA_ENC_TS_ENC
304            elif isinstance(self.underlayer, KRB_Ticket):
305                # AS-REP Ticket and TGS-REP Ticket
306                return 2, EncTicketPart
307            elif isinstance(self.underlayer, KRB_AS_REP):
308                # AS-REP encrypted part
309                return 3, EncASRepPart
310            elif isinstance(self.underlayer, KRB_AP_REQ) and isinstance(
311                self.underlayer.underlayer, PADATA
312            ):
313                # TGS-REQ PA-TGS-REQ Authenticator
314                return 7, KRB_Authenticator
315            elif isinstance(self.underlayer, KRB_TGS_REP):
316                # TGS-REP encrypted part
317                return 8, EncTGSRepPart
318            elif isinstance(self.underlayer, KRB_AP_REQ):
319                # AP-REQ Authenticator
320                return 11, KRB_Authenticator
321            elif isinstance(self.underlayer, KRB_AP_REP):
322                # AP-REP encrypted part
323                return 12, EncAPRepPart
324            elif isinstance(self.underlayer, KRB_PRIV):
325                # KRB-PRIV encrypted part
326                return 13, EncKrbPrivPart
327            elif isinstance(self.underlayer, KRB_CRED):
328                # KRB-CRED encrypted part
329                return 14, EncKrbCredPart
330            elif isinstance(self.underlayer, KrbFastArmoredReq):
331                # KEY_USAGE_FAST_ENC
332                return 51, KrbFastReq
333        raise ValueError(
334            "Could not guess key usage number. Please specify key_usage_number"
335        )
336
337    def decrypt(self, key, key_usage_number=None, cls=None):
338        """
339        Decrypt and return the data contained in cipher.
340
341        :param key: the key to use for decryption
342        :param key_usage_number: (optional) specify the key usage number.
343                                 Guessed otherwise
344        :param cls: (optional) the class of the decrypted payload
345                               Guessed otherwise (or bytes)
346        """
347        if key_usage_number is None:
348            key_usage_number, cls = self.get_usage()
349        d = key.decrypt(key_usage_number, self.cipher.val)
350        if cls:
351            try:
352                return cls(d)
353            except BER_Decoding_Error:
354                if cls == EncASRepPart:
355                    # https://datatracker.ietf.org/doc/html/rfc4120#section-5.4.2
356                    # "Compatibility note: Some implementations unconditionally send an
357                    # encrypted EncTGSRepPart (application tag number 26) in this field
358                    # regardless of whether the reply is a AS-REP or a TGS-REP.  In the
359                    # interest of compatibility, implementors MAY relax the check on the
360                    # tag number of the decrypted ENC-PART."
361                    try:
362                        res = EncTGSRepPart(d)
363                        # https://github.com/krb5/krb5/blob/48ccd81656381522d1f9ccb8705c13f0266a46ab/src/lib/krb5/asn.1/asn1_k_encode.c#L1128
364                        # This is a bug because as the RFC clearly says above, we're
365                        # perfectly in our right to be strict on this. (MAY)
366                        log_runtime.warning(
367                            "Implementation bug detected. This looks like MIT Kerberos."
368                        )
369                        return res
370                    except BER_Decoding_Error:
371                        pass
372                raise
373        return d
374
375    def encrypt(self, key, text, confounder=None, key_usage_number=None):
376        """
377        Encrypt text and set it into cipher.
378
379        :param key: the key to use for encryption
380        :param text: the bytes value to encode
381        :param confounder: (optional) specify the confounder bytes. Random otherwise
382        :param key_usage_number: (optional) specify the key usage number.
383                                 Guessed otherwise
384        """
385        if key_usage_number is None:
386            key_usage_number = self.get_usage()[0]
387        self.etype = key.etype
388        self.cipher = ASN1_STRING(
389            key.encrypt(key_usage_number, text, confounder=confounder)
390        )
391
392
393class EncryptionKey(ASN1_Packet):
394    ASN1_codec = ASN1_Codecs.BER
395    ASN1_root = ASN1F_SEQUENCE(
396        ASN1F_enum_INTEGER("keytype", 0, _KRB_E_TYPES, explicit_tag=0xA0),
397        ASN1F_STRING("keyvalue", "", explicit_tag=0xA1),
398    )
399
400    def toKey(self):
401        from scapy.libs.rfc3961 import Key
402
403        return Key(
404            etype=self.keytype.val,
405            key=self.keyvalue.val,
406        )
407
408    @classmethod
409    def fromKey(self, key):
410        return EncryptionKey(
411            keytype=key.etype,
412            keyvalue=key.key,
413        )
414
415
416class _Checksum_Field(ASN1F_STRING_PacketField):
417    def m2i(self, pkt, s):
418        val = super(_Checksum_Field, self).m2i(pkt, s)
419        if not val[0].val:
420            return val
421        if pkt.cksumtype.val == 0x8003:
422            # Special case per RFC 4121
423            return KRB_AuthenticatorChecksum(val[0].val, _underlayer=pkt), val[1]
424        return val
425
426
427class Checksum(ASN1_Packet):
428    ASN1_codec = ASN1_Codecs.BER
429    ASN1_root = ASN1F_SEQUENCE(
430        ASN1F_enum_INTEGER(
431            "cksumtype",
432            0,
433            _KRB_S_TYPES,
434            explicit_tag=0xA0,
435        ),
436        _Checksum_Field("checksum", "", explicit_tag=0xA1),
437    )
438
439    def get_usage(self):
440        """
441        Get current key usage number
442        """
443        # RFC 4120 sect 7.5.1
444        if self.underlayer:
445            if isinstance(self.underlayer, KRB_Authenticator):
446                # TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum
447                # (n°10 should never happen as we use RFC4121)
448                return 6
449            elif isinstance(self.underlayer, PA_FOR_USER):
450                # [MS-SFU] sect 2.2.1
451                return 17
452            elif isinstance(self.underlayer, PA_S4U_X509_USER):
453                # [MS-SFU] sect 2.2.1
454                return 17
455            elif isinstance(self.underlayer, AD_KDCIssued):
456                # AD-KDC-ISSUED checksum
457                return 19
458            elif isinstance(self.underlayer, KrbFastArmoredReq):
459                # KEY_USAGE_FAST_REQ_CHKSUM
460                return 50
461        raise ValueError(
462            "Could not guess key usage number. Please specify key_usage_number"
463        )
464
465    def verify(self, key, text, key_usage_number=None):
466        """
467        Decrypt and return the data contained in cipher.
468
469        :param key: the key to use to check the checksum
470        :param text: the bytes to verify
471        :param key_usage_number: (optional) specify the key usage number.
472                                 Guessed otherwise
473        """
474        if key_usage_number is None:
475            key_usage_number = self.get_usage()
476        key.verify_checksum(key_usage_number, text, self.checksum.val)
477
478    def make(self, key, text, key_usage_number=None, cksumtype=None):
479        """
480        Encrypt text and set it into cipher.
481
482        :param key: the key to use to make the checksum
483        :param text: the bytes to make a checksum of
484        :param key_usage_number: (optional) specify the key usage number.
485                                 Guessed otherwise
486        """
487        if key_usage_number is None:
488            key_usage_number = self.get_usage()
489        self.cksumtype = cksumtype or key.cksumtype
490        self.checksum = ASN1_STRING(
491            key.make_checksum(
492                keyusage=key_usage_number,
493                text=text,
494                cksumtype=self.cksumtype,
495            )
496        )
497
498
499KerberosFlags = ASN1F_FLAGS
500
501_ADDR_TYPES = {
502    # RFC4120 sect 7.5.3
503    0x02: "IPv4",
504    0x03: "Directional",
505    0x05: "ChaosNet",
506    0x06: "XNS",
507    0x07: "ISO",
508    0x0C: "DECNET Phase IV",
509    0x10: "AppleTalk DDP",
510    0x14: "NetBios",
511    0x18: "IPv6",
512}
513
514
515class HostAddress(ASN1_Packet):
516    ASN1_codec = ASN1_Codecs.BER
517    ASN1_root = ASN1F_SEQUENCE(
518        ASN1F_enum_INTEGER(
519            "addrType",
520            0,
521            _ADDR_TYPES,
522            explicit_tag=0xA0,
523        ),
524        ASN1F_STRING("address", "", explicit_tag=0xA1),
525    )
526
527
528HostAddresses = lambda name, **kwargs: ASN1F_SEQUENCE_OF(
529    name, [], HostAddress, **kwargs
530)
531
532
533_AUTHORIZATIONDATA_VALUES = {
534    # Filled below
535}
536
537
538class _AuthorizationData_value_Field(ASN1F_STRING_PacketField):
539    def m2i(self, pkt, s):
540        val = super(_AuthorizationData_value_Field, self).m2i(pkt, s)
541        if not val[0].val:
542            return val
543        if pkt.adType.val in _AUTHORIZATIONDATA_VALUES:
544            return (
545                _AUTHORIZATIONDATA_VALUES[pkt.adType.val](val[0].val, _underlayer=pkt),
546                val[1],
547            )
548        return val
549
550
551_AD_TYPES = {
552    # RFC4120 sect 7.5.4
553    1: "AD-IF-RELEVANT",
554    2: "AD-INTENDED-FOR-SERVER",
555    3: "AD-INTENDED-FOR-APPLICATION-CLASS",
556    4: "AD-KDC-ISSUED",
557    5: "AD-AND-OR",
558    6: "AD-MANDATORY-TICKET-EXTENSIONS",
559    7: "AD-IN-TICKET-EXTENSIONS",
560    8: "AD-MANDATORY-FOR-KDC",
561    64: "OSF-DCE",
562    65: "SESAME",
563    66: "AD-OSD-DCE-PKI-CERTID",
564    128: "AD-WIN2K-PAC",
565    129: "AD-ETYPE-NEGOTIATION",
566    # [MS-KILE] additions
567    141: "KERB-AUTH-DATA-TOKEN-RESTRICTIONS",
568    142: "KERB-LOCAL",
569    143: "AD-AUTH-DATA-AP-OPTIONS",
570    144: "KERB-AUTH-DATA-CLIENT-TARGET",
571}
572
573
574class AuthorizationDataItem(ASN1_Packet):
575    ASN1_codec = ASN1_Codecs.BER
576    ASN1_root = ASN1F_SEQUENCE(
577        ASN1F_enum_INTEGER(
578            "adType",
579            0,
580            _AD_TYPES,
581            explicit_tag=0xA0,
582        ),
583        _AuthorizationData_value_Field("adData", "", explicit_tag=0xA1),
584    )
585
586
587class AuthorizationData(ASN1_Packet):
588    ASN1_codec = ASN1_Codecs.BER
589    ASN1_root = ASN1F_SEQUENCE_OF(
590        "seq", [AuthorizationDataItem()], AuthorizationDataItem
591    )
592
593
594AD_IF_RELEVANT = AuthorizationData
595_AUTHORIZATIONDATA_VALUES[1] = AD_IF_RELEVANT
596
597
598class AD_KDCIssued(ASN1_Packet):
599    ASN1_codec = ASN1_Codecs.BER
600    ASN1_root = ASN1F_SEQUENCE(
601        ASN1F_PACKET("adChecksum", Checksum(), Checksum, explicit_tag=0xA0),
602        ASN1F_optional(
603            Realm("iRealm", "", explicit_tag=0xA1),
604        ),
605        ASN1F_optional(ASN1F_PACKET("iSname", None, PrincipalName, explicit_tag=0xA2)),
606        ASN1F_PACKET("elements", None, AuthorizationData, explicit_tag=0xA3),
607    )
608
609
610_AUTHORIZATIONDATA_VALUES[4] = AD_KDCIssued
611
612
613class AD_AND_OR(ASN1_Packet):
614    ASN1_codec = ASN1_Codecs.BER
615    ASN1_root = ASN1F_SEQUENCE(
616        Int32("conditionCount", 0, explicit_tag=0xA0),
617        ASN1F_PACKET("elements", None, AuthorizationData, explicit_tag=0xA1),
618    )
619
620
621_AUTHORIZATIONDATA_VALUES[5] = AD_AND_OR
622
623ADMANDATORYFORKDC = AuthorizationData
624_AUTHORIZATIONDATA_VALUES[8] = ADMANDATORYFORKDC
625
626
627# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xml
628_PADATA_TYPES = {
629    1: "PA-TGS-REQ",
630    2: "PA-ENC-TIMESTAMP",
631    3: "PA-PW-SALT",
632    11: "PA-ETYPE-INFO",
633    14: "PA-PK-AS-REQ-OLD",
634    15: "PA-PK-AS-REP-OLD",
635    16: "PA-PK-AS-REQ",
636    17: "PA-PK-AS-REP",
637    19: "PA-ETYPE-INFO2",
638    20: "PA-SVR-REFERRAL-INFO",
639    128: "PA-PAC-REQUEST",
640    129: "PA-FOR-USER",
641    130: "PA-FOR-X509-USER",
642    131: "PA-FOR-CHECK_DUPS",
643    132: "PA-AS-CHECKSUM",
644    133: "PA-FX-COOKIE",
645    134: "PA-AUTHENTICATION-SET",
646    135: "PA-AUTH-SET-SELECTED",
647    136: "PA-FX-FAST",
648    137: "PA-FX-ERROR",
649    138: "PA-ENCRYPTED-CHALLENGE",
650    141: "PA-OTP-CHALLENGE",
651    142: "PA-OTP-REQUEST",
652    143: "PA-OTP-CONFIRM",
653    144: "PA-OTP-PIN-CHANGE",
654    145: "PA-EPAK-AS-REQ",
655    146: "PA-EPAK-AS-REP",
656    147: "PA-PKINIT-KX",
657    148: "PA-PKU2U-NAME",
658    149: "PA-REQ-ENC-PA-REP",
659    150: "PA-AS-FRESHNESS",
660    151: "PA-SPAKE",
661    161: "KERB-KEY-LIST-REQ",
662    162: "KERB-KEY-LIST-REP",
663    165: "PA-SUPPORTED-ENCTYPES",
664    166: "PA-EXTENDED-ERROR",
665    167: "PA-PAC-OPTIONS",
666}
667
668_PADATA_CLASSES = {
669    # Filled elsewhere in this file
670}
671
672
673# RFC4120
674
675
676class _PADATA_value_Field(ASN1F_STRING_PacketField):
677    """
678    A special field that properly dispatches PA-DATA values according to
679    padata-type and if the paquet is a request or a response.
680    """
681
682    def m2i(self, pkt, s):
683        val = super(_PADATA_value_Field, self).m2i(pkt, s)
684        if pkt.padataType.val in _PADATA_CLASSES:
685            cls = _PADATA_CLASSES[pkt.padataType.val]
686            if isinstance(cls, tuple):
687                is_reply = (
688                    pkt.underlayer.underlayer is not None
689                    and isinstance(pkt.underlayer.underlayer, KRB_ERROR)
690                ) or isinstance(pkt.underlayer, (KRB_AS_REP, KRB_TGS_REP))
691                cls = cls[is_reply]
692            if not val[0].val:
693                return val
694            return cls(val[0].val, _underlayer=pkt), val[1]
695        return val
696
697
698class PADATA(ASN1_Packet):
699    ASN1_codec = ASN1_Codecs.BER
700    ASN1_root = ASN1F_SEQUENCE(
701        ASN1F_enum_INTEGER("padataType", 0, _PADATA_TYPES, explicit_tag=0xA1),
702        _PADATA_value_Field(
703            "padataValue",
704            "",
705            explicit_tag=0xA2,
706        ),
707    )
708
709
710# RFC 4120 sect 5.2.7.2
711
712
713class PA_ENC_TS_ENC(ASN1_Packet):
714    ASN1_codec = ASN1_Codecs.BER
715    ASN1_root = ASN1F_SEQUENCE(
716        KerberosTime("patimestamp", GeneralizedTime(), explicit_tag=0xA0),
717        ASN1F_optional(Microseconds("pausec", 0, explicit_tag=0xA1)),
718    )
719
720
721_PADATA_CLASSES[2] = EncryptedData
722
723
724# RFC 4120 sect 5.2.7.4
725
726
727class ETYPE_INFO_ENTRY(ASN1_Packet):
728    ASN1_codec = ASN1_Codecs.BER
729    ASN1_root = ASN1F_SEQUENCE(
730        ASN1F_enum_INTEGER("etype", 0x1, _KRB_E_TYPES, explicit_tag=0xA0),
731        ASN1F_optional(
732            ASN1F_STRING("salt", "", explicit_tag=0xA1),
733        ),
734    )
735
736
737class ETYPE_INFO(ASN1_Packet):
738    ASN1_codec = ASN1_Codecs.BER
739    ASN1_root = ASN1F_SEQUENCE_OF("seq", [ETYPE_INFO_ENTRY()], ETYPE_INFO_ENTRY)
740
741
742_PADATA_CLASSES[11] = ETYPE_INFO
743
744# RFC 4120 sect 5.2.7.5
745
746
747class ETYPE_INFO_ENTRY2(ASN1_Packet):
748    ASN1_codec = ASN1_Codecs.BER
749    ASN1_root = ASN1F_SEQUENCE(
750        ASN1F_enum_INTEGER("etype", 0x1, _KRB_E_TYPES, explicit_tag=0xA0),
751        ASN1F_optional(
752            KerberosString("salt", "", explicit_tag=0xA1),
753        ),
754        ASN1F_optional(
755            ASN1F_STRING("s2kparams", "", explicit_tag=0xA2),
756        ),
757    )
758
759
760class ETYPE_INFO2(ASN1_Packet):
761    ASN1_codec = ASN1_Codecs.BER
762    ASN1_root = ASN1F_SEQUENCE_OF("seq", [ETYPE_INFO_ENTRY2()], ETYPE_INFO_ENTRY2)
763
764
765_PADATA_CLASSES[19] = ETYPE_INFO2
766
767# PADATA Extended with RFC6113
768
769
770class PA_AUTHENTICATION_SET_ELEM(ASN1_Packet):
771    ASN1_codec = ASN1_Codecs.BER
772    ASN1_root = ASN1F_SEQUENCE(
773        Int32("paType", 0, explicit_tag=0xA0),
774        ASN1F_optional(
775            ASN1F_STRING("paHint", "", explicit_tag=0xA1),
776        ),
777        ASN1F_optional(
778            ASN1F_STRING("paValue", "", explicit_tag=0xA2),
779        ),
780    )
781
782
783class PA_AUTHENTICATION_SET(ASN1_Packet):
784    ASN1_codec = ASN1_Codecs.BER
785    ASN1_root = ASN1F_SEQUENCE_OF(
786        "elems", [PA_AUTHENTICATION_SET_ELEM()], PA_AUTHENTICATION_SET_ELEM
787    )
788
789
790_PADATA_CLASSES[134] = PA_AUTHENTICATION_SET
791
792
793# [MS-KILE] sect 2.2.3
794
795
796class PA_PAC_REQUEST(ASN1_Packet):
797    ASN1_codec = ASN1_Codecs.BER
798    ASN1_root = ASN1F_SEQUENCE(
799        ASN1F_BOOLEAN("includePac", True, explicit_tag=0xA0),
800    )
801
802
803_PADATA_CLASSES[128] = PA_PAC_REQUEST
804
805
806# [MS-KILE] sect 2.2.5
807
808
809class LSAP_TOKEN_INFO_INTEGRITY(Packet):
810    fields_desc = [
811        FlagsField(
812            "Flags",
813            0,
814            -32,
815            {
816                0x00000001: "UAC-Restricted",
817            },
818        ),
819        LEIntEnumField(
820            "TokenIL",
821            0x00002000,
822            {
823                0x00000000: "Untrusted",
824                0x00001000: "Low",
825                0x00002000: "Medium",
826                0x00003000: "High",
827                0x00004000: "System",
828                0x00005000: "Protected process",
829            },
830        ),
831        XStrFixedLenField("MachineID", b"", length=32),
832    ]
833
834
835# [MS-KILE] sect 2.2.6
836
837
838class _KerbAdRestrictionEntry_Field(ASN1F_STRING_PacketField):
839    def m2i(self, pkt, s):
840        val = super(_KerbAdRestrictionEntry_Field, self).m2i(pkt, s)
841        if not val[0].val:
842            return val
843        if pkt.restrictionType.val == 0x0000:  # LSAP_TOKEN_INFO_INTEGRITY
844            return LSAP_TOKEN_INFO_INTEGRITY(val[0].val, _underlayer=pkt), val[1]
845        return val
846
847
848class KERB_AD_RESTRICTION_ENTRY(ASN1_Packet):
849    name = "KERB-AD-RESTRICTION-ENTRY"
850    ASN1_codec = ASN1_Codecs.BER
851    ASN1_root = ASN1F_SEQUENCE(
852        ASN1F_SEQUENCE(
853            ASN1F_enum_INTEGER(
854                "restrictionType",
855                0,
856                {0: "LSAP_TOKEN_INFO_INTEGRITY"},
857                explicit_tag=0xA0,
858            ),
859            _KerbAdRestrictionEntry_Field("restriction", b"", explicit_tag=0xA1),
860        )
861    )
862
863
864_AUTHORIZATIONDATA_VALUES[141] = KERB_AD_RESTRICTION_ENTRY
865
866
867# [MS-KILE] sect 3.2.5.8
868
869
870class KERB_AUTH_DATA_AP_OPTIONS(Packet):
871    name = "KERB-AUTH-DATA-AP-OPTIONS"
872    fields_desc = [
873        LEIntEnumField(
874            "apOptions",
875            0x4000,
876            {
877                0x4000: "KERB_AP_OPTIONS_CBT",
878                0x8000: "KERB_AP_OPTIONS_UNVERIFIED_TARGET_NAME",
879            },
880        ),
881    ]
882
883
884_AUTHORIZATIONDATA_VALUES[143] = KERB_AUTH_DATA_AP_OPTIONS
885
886
887# This has no doc..? [MS-KILE] only mentions its name.
888
889
890class KERB_AUTH_DATA_CLIENT_TARGET(Packet):
891    name = "KERB-AD-TARGET-PRINCIPAL"
892    fields_desc = [
893        StrFieldUtf16("spn", ""),
894    ]
895
896
897_AUTHORIZATIONDATA_VALUES[144] = KERB_AUTH_DATA_CLIENT_TARGET
898
899
900# RFC6806 sect 6
901
902
903class KERB_AD_LOGIN_ALIAS(ASN1_Packet):
904    ASN1_codec = ASN1_Codecs.BER
905    ASN1_root = ASN1F_SEQUENCE(ASN1F_SEQUENCE_OF("loginAliases", [], PrincipalName))
906
907
908_AUTHORIZATIONDATA_VALUES[80] = KERB_AD_LOGIN_ALIAS
909
910
911# [MS-KILE] sect 2.2.8
912
913
914class PA_SUPPORTED_ENCTYPES(Packet):
915    fields_desc = [
916        FlagsField(
917            "flags",
918            0,
919            -32,
920            [
921                "DES-CBC-CRC",
922                "DES-CBC-MD5",
923                "RC4-HMAC",
924                "AES128-CTS-HMAC-SHA1-96",
925                "AES256-CTS-HMAC-SHA1-96",
926            ]
927            + ["bit_%d" % i for i in range(11)]
928            + [
929                "FAST-supported",
930                "Compount-identity-supported",
931                "Claims-supported",
932                "Resource-SID-compression-disabled",
933            ],
934        )
935    ]
936
937
938_PADATA_CLASSES[165] = PA_SUPPORTED_ENCTYPES
939
940# [MS-KILE] sect 2.2.10
941
942
943class PA_PAC_OPTIONS(ASN1_Packet):
944    ASN1_codec = ASN1_Codecs.BER
945    ASN1_root = ASN1F_SEQUENCE(
946        KerberosFlags(
947            "options",
948            "",
949            [
950                "Claims",
951                "Branch-Aware",
952                "Forward-to-Full-DC",
953                "Resource-based-constrained-delegation",  # [MS-SFU] 2.2.5
954            ],
955            explicit_tag=0xA0,
956        )
957    )
958
959
960_PADATA_CLASSES[167] = PA_PAC_OPTIONS
961
962# [MS-KILE] sect 2.2.11
963
964
965class KERB_KEY_LIST_REQ(ASN1_Packet):
966    ASN1_codec = ASN1_Codecs.BER
967    ASN1_root = ASN1F_SEQUENCE_OF(
968        "keytypes",
969        [],
970        ASN1F_enum_INTEGER("", 0, _KRB_E_TYPES),
971    )
972
973
974_PADATA_CLASSES[161] = KERB_KEY_LIST_REQ
975
976# [MS-KILE] sect 2.2.12
977
978
979class KERB_KEY_LIST_REP(ASN1_Packet):
980    ASN1_codec = ASN1_Codecs.BER
981    ASN1_root = ASN1F_SEQUENCE_OF(
982        "keys",
983        [],
984        ASN1F_PACKET("", None, EncryptionKey),
985    )
986
987
988_PADATA_CLASSES[162] = KERB_KEY_LIST_REP
989
990# [MS-KILE] sect 2.2.13
991
992
993class KERB_SUPERSEDED_BY_USER(ASN1_Packet):
994    ASN1_codec = ASN1_Codecs.BER
995    ASN1_root = ASN1F_SEQUENCE(
996        ASN1F_PACKET("name", None, PrincipalName, explicit_tag=0xA0),
997        Realm("realm", None, explicit_tag=0xA1),
998    )
999
1000
1001# [MS-KILE] sect 2.2.14
1002
1003
1004class KERB_DMSA_KEY_PACKAGE(ASN1_Packet):
1005    ASN1_codec = ASN1_Codecs.BER
1006    ASN1_root = ASN1F_SEQUENCE(
1007        ASN1F_SEQUENCE_OF(
1008            "currentKeys",
1009            [],
1010            ASN1F_PACKET("", None, EncryptionKey),
1011            explicit_tag=0xA0,
1012        ),
1013        ASN1F_optional(
1014            ASN1F_SEQUENCE_OF(
1015                "previousKeys",
1016                [],
1017                ASN1F_PACKET("", None, EncryptionKey),
1018                explicit_tag=0xA0,
1019            ),
1020        ),
1021        KerberosTime("expirationInterval", GeneralizedTime(), explicit_tag=0xA2),
1022        KerberosTime("fetchInterval", GeneralizedTime(), explicit_tag=0xA4),
1023    )
1024
1025
1026# RFC6113 sect 5.4.1
1027
1028
1029class _KrbFastArmor_value_Field(ASN1F_STRING_PacketField):
1030    def m2i(self, pkt, s):
1031        val = super(_KrbFastArmor_value_Field, self).m2i(pkt, s)
1032        if not val[0].val:
1033            return val
1034        if pkt.armorType.val == 1:  # FX_FAST_ARMOR_AP_REQUEST
1035            return KRB_AP_REQ(val[0].val, _underlayer=pkt), val[1]
1036        return val
1037
1038
1039class KrbFastArmor(ASN1_Packet):
1040    ASN1_codec = ASN1_Codecs.BER
1041    ASN1_root = ASN1F_SEQUENCE(
1042        ASN1F_enum_INTEGER(
1043            "armorType", 1, {1: "FX_FAST_ARMOR_AP_REQUEST"}, explicit_tag=0xA0
1044        ),
1045        _KrbFastArmor_value_Field("armorValue", "", explicit_tag=0xA1),
1046    )
1047
1048
1049# RFC6113 sect 5.4.2
1050
1051
1052class KrbFastArmoredReq(ASN1_Packet):
1053    ASN1_codec = ASN1_Codecs.BER
1054    ASN1_root = ASN1F_SEQUENCE(
1055        ASN1F_SEQUENCE(
1056            ASN1F_optional(
1057                ASN1F_PACKET("armor", KrbFastArmor(), KrbFastArmor, explicit_tag=0xA0)
1058            ),
1059            ASN1F_PACKET("reqChecksum", Checksum(), Checksum, explicit_tag=0xA1),
1060            ASN1F_PACKET("encFastReq", None, EncryptedData, explicit_tag=0xA2),
1061        )
1062    )
1063
1064
1065class PA_FX_FAST_REQUEST(ASN1_Packet):
1066    ASN1_codec = ASN1_Codecs.BER
1067    ASN1_root = ASN1F_CHOICE(
1068        "armoredData",
1069        ASN1_STRING(""),
1070        ASN1F_PACKET("req", KrbFastArmoredReq, KrbFastArmoredReq, implicit_tag=0xA0),
1071    )
1072
1073
1074# RFC6113 sect 5.4.3
1075
1076
1077class KrbFastArmoredRep(ASN1_Packet):
1078    ASN1_codec = ASN1_Codecs.BER
1079    ASN1_root = ASN1F_SEQUENCE(
1080        ASN1F_SEQUENCE(
1081            ASN1F_PACKET("encFastRep", None, EncryptedData, explicit_tag=0xA0),
1082        )
1083    )
1084
1085
1086class PA_FX_FAST_REPLY(ASN1_Packet):
1087    ASN1_codec = ASN1_Codecs.BER
1088    ASN1_root = ASN1F_CHOICE(
1089        "armoredData",
1090        ASN1_STRING(""),
1091        ASN1F_PACKET("req", KrbFastArmoredRep, KrbFastArmoredRep, implicit_tag=0xA0),
1092    )
1093
1094
1095class KrbFastFinished(ASN1_Packet):
1096    ASN1_codec = ASN1_Codecs.BER
1097    ASN1_root = ASN1F_SEQUENCE(
1098        KerberosTime("timestamp", GeneralizedTime(), explicit_tag=0xA0),
1099        Microseconds("usec", 0, explicit_tag=0xA1),
1100        Realm("crealm", "", explicit_tag=0xA2),
1101        ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA3),
1102        ASN1F_PACKET("ticketChecksum", Checksum(), Checksum, explicit_tag=0xA4),
1103    )
1104
1105
1106class KrbFastResponse(ASN1_Packet):
1107    ASN1_codec = ASN1_Codecs.BER
1108    ASN1_root = ASN1F_SEQUENCE(
1109        ASN1F_SEQUENCE_OF("padata", [PADATA()], PADATA, explicit_tag=0xA0),
1110        ASN1F_optional(
1111            ASN1F_PACKET("stengthenKey", None, EncryptionKey, explicit_tag=0xA1)
1112        ),
1113        ASN1F_optional(
1114            ASN1F_PACKET(
1115                "finished", KrbFastFinished(), KrbFastFinished, explicit_tag=0xA2
1116            )
1117        ),
1118        UInt32("nonce", 0, explicit_tag=0xA3),
1119    )
1120
1121
1122_PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY)
1123
1124# RFC 4556
1125
1126
1127# sect 3.2.1
1128
1129
1130class ExternalPrincipalIdentifier(ASN1_Packet):
1131    ASN1_codec = ASN1_Codecs.BER
1132    ASN1_root = ASN1F_SEQUENCE(
1133        ASN1F_optional(
1134            ASN1F_STRING("subjectName", "", implicit_tag=0xA0),
1135        ),
1136        ASN1F_optional(
1137            ASN1F_STRING("issuerAndSerialNumber", "", implicit_tag=0xA1),
1138        ),
1139        ASN1F_optional(
1140            ASN1F_STRING("subjectKeyIdentifier", "", implicit_tag=0xA2),
1141        ),
1142    )
1143
1144
1145class PA_PK_AS_REQ(ASN1_Packet):
1146    ASN1_codec = ASN1_Codecs.BER
1147    ASN1_root = ASN1F_SEQUENCE(
1148        ASN1F_STRING("signedAuthpack", "", implicit_tag=0xA0),
1149        ASN1F_optional(
1150            ASN1F_SEQUENCE_OF(
1151                "trustedCertifiers",
1152                [ExternalPrincipalIdentifier()],
1153                ExternalPrincipalIdentifier,
1154                explicit_tag=0xA1,
1155            ),
1156        ),
1157        ASN1F_optional(
1158            ASN1F_STRING("kdcPkId", "", implicit_tag=0xA2),
1159        ),
1160    )
1161
1162
1163_PADATA_CLASSES[16] = PA_PK_AS_REQ
1164
1165# sect 3.2.3
1166
1167
1168class DHRepInfo(ASN1_Packet):
1169    ASN1_codec = ASN1_Codecs.BER
1170    ASN1_root = ASN1F_SEQUENCE(
1171        ASN1F_STRING("dhSignedData", "", implicit_tag=0xA0),
1172        ASN1F_optional(
1173            ASN1F_STRING("serverDHNonce", "", explicit_tag=0xA1),
1174        ),
1175    )
1176
1177
1178class EncKeyPack(ASN1_Packet):
1179    ASN1_codec = ASN1_Codecs.BER
1180    ASN1_root = ASN1F_STRING("encKeyPack", "")
1181
1182
1183class PA_PK_AS_REP(ASN1_Packet):
1184    ASN1_codec = ASN1_Codecs.BER
1185    ASN1_root = ASN1F_CHOICE(
1186        "rep",
1187        ASN1_STRING(""),
1188        ASN1F_PACKET("dhInfo", DHRepInfo(), DHRepInfo, explicit_tag=0xA0),
1189        ASN1F_PACKET("encKeyPack", EncKeyPack(), EncKeyPack, explicit_tag=0xA1),
1190    )
1191
1192
1193_PADATA_CLASSES[17] = PA_PK_AS_REP
1194
1195# [MS-SFU]
1196
1197
1198# sect 2.2.1
1199class PA_FOR_USER(ASN1_Packet):
1200    ASN1_codec = ASN1_Codecs.BER
1201    ASN1_root = ASN1F_SEQUENCE(
1202        ASN1F_PACKET("userName", PrincipalName(), PrincipalName, explicit_tag=0xA0),
1203        Realm("userRealm", "", explicit_tag=0xA1),
1204        ASN1F_PACKET("cksum", Checksum(), Checksum, explicit_tag=0xA2),
1205        KerberosString("authPackage", "Kerberos", explicit_tag=0xA3),
1206    )
1207
1208
1209_PADATA_CLASSES[129] = PA_FOR_USER
1210
1211
1212# sect 2.2.2
1213
1214
1215class S4UUserID(ASN1_Packet):
1216    ASN1_codec = ASN1_Codecs.BER
1217    ASN1_root = ASN1F_SEQUENCE(
1218        UInt32("nonce", 0, explicit_tag=0xA0),
1219        ASN1F_optional(
1220            ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA1),
1221        ),
1222        Realm("crealm", "", explicit_tag=0xA2),
1223        ASN1F_optional(
1224            ASN1F_STRING("subjectCertificate", None, explicit_tag=0xA3),
1225        ),
1226        ASN1F_optional(
1227            ASN1F_FLAGS(
1228                "options",
1229                "",
1230                [
1231                    "reserved",
1232                    "KDC_CHECK_LOGON_HOUR_RESTRICTIONS",
1233                    "KDC_KEY_USAGE_27",
1234                ],
1235                explicit_tag=0xA4,
1236            )
1237        ),
1238    )
1239
1240
1241class PA_S4U_X509_USER(ASN1_Packet):
1242    ASN1_codec = ASN1_Codecs.BER
1243    ASN1_root = ASN1F_SEQUENCE(
1244        ASN1F_PACKET("userId", S4UUserID(), S4UUserID, explicit_tag=0xA0),
1245        ASN1F_PACKET("checksum", Checksum(), Checksum, explicit_tag=0xA1),
1246    )
1247
1248
1249_PADATA_CLASSES[130] = PA_S4U_X509_USER
1250
1251
1252# Back to RFC4120
1253
1254# sect 5.10
1255KRB_MSG_TYPES = {
1256    1: "Ticket",
1257    2: "Authenticator",
1258    3: "EncTicketPart",
1259    10: "AS-REQ",
1260    11: "AS-REP",
1261    12: "TGS-REQ",
1262    13: "TGS-REP",
1263    14: "AP-REQ",
1264    15: "AP-REP",
1265    16: "KRB-TGT-REQ",  # U2U
1266    17: "KRB-TGT-REP",  # U2U
1267    20: "KRB-SAFE",
1268    21: "KRB-PRIV",
1269    22: "KRB-CRED",
1270    25: "EncASRepPart",
1271    26: "EncTGSRepPart",
1272    27: "EncAPRepPart",
1273    28: "EncKrbPrivPart",
1274    29: "EnvKrbCredPart",
1275    30: "KRB-ERROR",
1276}
1277
1278# sect 5.3
1279
1280
1281class KRB_Ticket(ASN1_Packet):
1282    ASN1_codec = ASN1_Codecs.BER
1283    ASN1_root = ASN1F_SEQUENCE(
1284        ASN1F_SEQUENCE(
1285            ASN1F_INTEGER("tktVno", 5, explicit_tag=0xA0),
1286            Realm("realm", "", explicit_tag=0xA1),
1287            ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xA2),
1288            ASN1F_PACKET("encPart", EncryptedData(), EncryptedData, explicit_tag=0xA3),
1289        ),
1290        implicit_tag=ASN1_Class_KRB.Ticket,
1291    )
1292
1293    def getSPN(self):
1294        return "%s@%s" % (
1295            "/".join(x.val.decode() for x in self.sname.nameString),
1296            self.realm.val.decode(),
1297        )
1298
1299
1300class TransitedEncoding(ASN1_Packet):
1301    ASN1_codec = ASN1_Codecs.BER
1302    ASN1_root = ASN1F_SEQUENCE(
1303        Int32("trType", 0, explicit_tag=0xA0),
1304        ASN1F_STRING("contents", "", explicit_tag=0xA1),
1305    )
1306
1307
1308_TICKET_FLAGS = [
1309    "reserved",
1310    "forwardable",
1311    "forwarded",
1312    "proxiable",
1313    "proxy",
1314    "may-postdate",
1315    "postdated",
1316    "invalid",
1317    "renewable",
1318    "initial",
1319    "pre-authent",
1320    "hw-authent",
1321    "transited-since-policy-checked",
1322    "ok-as-delegate",
1323    "unused",
1324    "canonicalize",  # RFC6806
1325    "anonymous",  # RFC6112 + RFC8129
1326]
1327
1328
1329class EncTicketPart(ASN1_Packet):
1330    ASN1_codec = ASN1_Codecs.BER
1331    ASN1_root = ASN1F_SEQUENCE(
1332        ASN1F_SEQUENCE(
1333            KerberosFlags(
1334                "flags",
1335                "",
1336                _TICKET_FLAGS,
1337                explicit_tag=0xA0,
1338            ),
1339            ASN1F_PACKET("key", EncryptionKey(), EncryptionKey, explicit_tag=0xA1),
1340            Realm("crealm", "", explicit_tag=0xA2),
1341            ASN1F_PACKET("cname", PrincipalName(), PrincipalName, explicit_tag=0xA3),
1342            ASN1F_PACKET(
1343                "transited", TransitedEncoding(), TransitedEncoding, explicit_tag=0xA4
1344            ),
1345            KerberosTime("authtime", GeneralizedTime(), explicit_tag=0xA5),
1346            ASN1F_optional(
1347                KerberosTime("starttime", GeneralizedTime(), explicit_tag=0xA6)
1348            ),
1349            KerberosTime("endtime", GeneralizedTime(), explicit_tag=0xA7),
1350            ASN1F_optional(
1351                KerberosTime("renewTill", GeneralizedTime(), explicit_tag=0xA8),
1352            ),
1353            ASN1F_optional(
1354                HostAddresses("addresses", explicit_tag=0xA9),
1355            ),
1356            ASN1F_optional(
1357                ASN1F_PACKET(
1358                    "authorizationData", None, AuthorizationData, explicit_tag=0xAA
1359                ),
1360            ),
1361        ),
1362        implicit_tag=ASN1_Class_KRB.EncTicketPart,
1363    )
1364
1365
1366# sect 5.4.1
1367
1368
1369class KRB_KDC_REQ_BODY(ASN1_Packet):
1370    ASN1_codec = ASN1_Codecs.BER
1371    ASN1_root = ASN1F_SEQUENCE(
1372        KerberosFlags(
1373            "kdcOptions",
1374            "",
1375            [
1376                "reserved",
1377                "forwardable",
1378                "forwarded",
1379                "proxiable",
1380                "proxy",
1381                "allow-postdate",
1382                "postdated",
1383                "unused7",
1384                "renewable",
1385                "unused9",
1386                "unused10",
1387                "opt-hardware-auth",
1388                "unused12",
1389                "unused13",
1390                "cname-in-addl-tkt",  # [MS-SFU] sect 2.2.3
1391                "canonicalize",  # RFC6806
1392                "request-anonymous",  # RFC6112 + RFC8129
1393            ]
1394            + ["unused%d" % i for i in range(17, 26)]
1395            + [
1396                "disable-transited-check",
1397                "renewable-ok",
1398                "enc-tkt-in-skey",
1399                "unused29",
1400                "renew",
1401                "validate",
1402            ],
1403            explicit_tag=0xA0,
1404        ),
1405        ASN1F_optional(ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA1)),
1406        Realm("realm", "", explicit_tag=0xA2),
1407        ASN1F_optional(
1408            ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA3),
1409        ),
1410        ASN1F_optional(KerberosTime("from_", None, explicit_tag=0xA4)),
1411        KerberosTime("till", GeneralizedTime(), explicit_tag=0xA5),
1412        ASN1F_optional(KerberosTime("rtime", GeneralizedTime(), explicit_tag=0xA6)),
1413        UInt32("nonce", 0, explicit_tag=0xA7),
1414        ASN1F_SEQUENCE_OF("etype", [], Int32, explicit_tag=0xA8),
1415        ASN1F_optional(
1416            HostAddresses("addresses", explicit_tag=0xA9),
1417        ),
1418        ASN1F_optional(
1419            ASN1F_PACKET(
1420                "encAuthorizationData", None, EncryptedData, explicit_tag=0xAA
1421            ),
1422        ),
1423        ASN1F_optional(
1424            ASN1F_SEQUENCE_OF("additionalTickets", [], KRB_Ticket, explicit_tag=0xAB)
1425        ),
1426    )
1427
1428
1429KRB_KDC_REQ = ASN1F_SEQUENCE(
1430    ASN1F_INTEGER("pvno", 5, explicit_tag=0xA1),
1431    ASN1F_enum_INTEGER("msgType", 10, KRB_MSG_TYPES, explicit_tag=0xA2),
1432    ASN1F_optional(ASN1F_SEQUENCE_OF("padata", [], PADATA, explicit_tag=0xA3)),
1433    ASN1F_PACKET("reqBody", KRB_KDC_REQ_BODY(), KRB_KDC_REQ_BODY, explicit_tag=0xA4),
1434)
1435
1436
1437class KrbFastReq(ASN1_Packet):
1438    # RFC6113 sect 5.4.2
1439    ASN1_codec = ASN1_Codecs.BER
1440    ASN1_root = ASN1F_SEQUENCE(
1441        KerberosFlags(
1442            "fastOptions",
1443            "",
1444            [
1445                "RESERVED",
1446                "hide-client-names",
1447            ]
1448            + ["res%d" % i for i in range(2, 16)]
1449            + ["kdc-follow-referrals"],
1450            explicit_tag=0xA0,
1451        ),
1452        ASN1F_SEQUENCE_OF("padata", [PADATA()], PADATA, explicit_tag=0xA1),
1453        ASN1F_PACKET("reqBody", None, KRB_KDC_REQ_BODY, explicit_tag=0xA2),
1454    )
1455
1456
1457class KRB_AS_REQ(ASN1_Packet):
1458    ASN1_codec = ASN1_Codecs.BER
1459    ASN1_root = ASN1F_SEQUENCE(
1460        KRB_KDC_REQ,
1461        implicit_tag=ASN1_Class_KRB.AS_REQ,
1462    )
1463
1464
1465class KRB_TGS_REQ(ASN1_Packet):
1466    ASN1_codec = ASN1_Codecs.BER
1467    ASN1_root = ASN1F_SEQUENCE(
1468        KRB_KDC_REQ,
1469        implicit_tag=ASN1_Class_KRB.TGS_REQ,
1470    )
1471    msgType = ASN1_INTEGER(12)
1472
1473
1474# sect 5.4.2
1475
1476KRB_KDC_REP = ASN1F_SEQUENCE(
1477    ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1478    ASN1F_enum_INTEGER("msgType", 11, KRB_MSG_TYPES, explicit_tag=0xA1),
1479    ASN1F_optional(
1480        ASN1F_SEQUENCE_OF("padata", [], PADATA, explicit_tag=0xA2),
1481    ),
1482    Realm("crealm", "", explicit_tag=0xA3),
1483    ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA4),
1484    ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA5),
1485    ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA6),
1486)
1487
1488
1489class KRB_AS_REP(ASN1_Packet):
1490    ASN1_codec = ASN1_Codecs.BER
1491    ASN1_root = ASN1F_SEQUENCE(
1492        KRB_KDC_REP,
1493        implicit_tag=ASN1_Class_KRB.AS_REP,
1494    )
1495
1496
1497class KRB_TGS_REP(ASN1_Packet):
1498    ASN1_codec = ASN1_Codecs.BER
1499    ASN1_root = ASN1F_SEQUENCE(
1500        KRB_KDC_REP,
1501        implicit_tag=ASN1_Class_KRB.TGS_REP,
1502    )
1503
1504
1505class LastReqItem(ASN1_Packet):
1506    ASN1_codec = ASN1_Codecs.BER
1507    ASN1_root = ASN1F_SEQUENCE(
1508        Int32("lrType", 0, explicit_tag=0xA0),
1509        KerberosTime("lrValue", GeneralizedTime(), explicit_tag=0xA1),
1510    )
1511
1512
1513EncKDCRepPart = ASN1F_SEQUENCE(
1514    ASN1F_PACKET("key", None, EncryptionKey, explicit_tag=0xA0),
1515    ASN1F_SEQUENCE_OF("lastReq", [], LastReqItem, explicit_tag=0xA1),
1516    UInt32("nonce", 0, explicit_tag=0xA2),
1517    ASN1F_optional(
1518        KerberosTime("keyExpiration", GeneralizedTime(), explicit_tag=0xA3),
1519    ),
1520    KerberosFlags(
1521        "flags",
1522        "",
1523        _TICKET_FLAGS,
1524        explicit_tag=0xA4,
1525    ),
1526    KerberosTime("authtime", GeneralizedTime(), explicit_tag=0xA5),
1527    ASN1F_optional(
1528        KerberosTime("starttime", GeneralizedTime(), explicit_tag=0xA6),
1529    ),
1530    KerberosTime("endtime", GeneralizedTime(), explicit_tag=0xA7),
1531    ASN1F_optional(
1532        KerberosTime("renewTill", GeneralizedTime(), explicit_tag=0xA8),
1533    ),
1534    Realm("srealm", "", explicit_tag=0xA9),
1535    ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xAA),
1536    ASN1F_optional(
1537        HostAddresses("caddr", explicit_tag=0xAB),
1538    ),
1539    # RFC6806 sect 11
1540    ASN1F_optional(
1541        ASN1F_SEQUENCE_OF("encryptedPaData", [], PADATA, explicit_tag=0xAC),
1542    ),
1543)
1544
1545
1546class EncASRepPart(ASN1_Packet):
1547    ASN1_codec = ASN1_Codecs.BER
1548    ASN1_root = ASN1F_SEQUENCE(
1549        EncKDCRepPart,
1550        implicit_tag=ASN1_Class_KRB.EncASRepPart,
1551    )
1552
1553
1554class EncTGSRepPart(ASN1_Packet):
1555    ASN1_codec = ASN1_Codecs.BER
1556    ASN1_root = ASN1F_SEQUENCE(
1557        EncKDCRepPart,
1558        implicit_tag=ASN1_Class_KRB.EncTGSRepPart,
1559    )
1560
1561
1562# sect 5.5.1
1563
1564
1565class KRB_AP_REQ(ASN1_Packet):
1566    ASN1_codec = ASN1_Codecs.BER
1567    ASN1_root = ASN1F_SEQUENCE(
1568        ASN1F_SEQUENCE(
1569            ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1570            ASN1F_enum_INTEGER("msgType", 14, KRB_MSG_TYPES, explicit_tag=0xA1),
1571            KerberosFlags(
1572                "apOptions",
1573                "",
1574                [
1575                    "reserved",
1576                    "use-session-key",
1577                    "mutual-required",
1578                ],
1579                explicit_tag=0xA2,
1580            ),
1581            ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA3),
1582            ASN1F_PACKET("authenticator", None, EncryptedData, explicit_tag=0xA4),
1583        ),
1584        implicit_tag=ASN1_Class_KRB.AP_REQ,
1585    )
1586
1587
1588_PADATA_CLASSES[1] = KRB_AP_REQ
1589
1590
1591class KRB_Authenticator(ASN1_Packet):
1592    ASN1_codec = ASN1_Codecs.BER
1593    ASN1_root = ASN1F_SEQUENCE(
1594        ASN1F_SEQUENCE(
1595            ASN1F_INTEGER("authenticatorPvno", 5, explicit_tag=0xA0),
1596            Realm("crealm", "", explicit_tag=0xA1),
1597            ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA2),
1598            ASN1F_optional(
1599                ASN1F_PACKET("cksum", None, Checksum, explicit_tag=0xA3),
1600            ),
1601            Microseconds("cusec", 0, explicit_tag=0xA4),
1602            KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA5),
1603            ASN1F_optional(
1604                ASN1F_PACKET("subkey", None, EncryptionKey, explicit_tag=0xA6),
1605            ),
1606            ASN1F_optional(
1607                UInt32("seqNumber", 0, explicit_tag=0xA7),
1608            ),
1609            ASN1F_optional(
1610                ASN1F_PACKET(
1611                    "encAuthorizationData", None, AuthorizationData, explicit_tag=0xA8
1612                ),
1613            ),
1614        ),
1615        implicit_tag=ASN1_Class_KRB.Authenticator,
1616    )
1617
1618
1619# sect 5.5.2
1620
1621
1622class KRB_AP_REP(ASN1_Packet):
1623    ASN1_codec = ASN1_Codecs.BER
1624    ASN1_root = ASN1F_SEQUENCE(
1625        ASN1F_SEQUENCE(
1626            ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1627            ASN1F_enum_INTEGER("msgType", 15, KRB_MSG_TYPES, explicit_tag=0xA1),
1628            ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA2),
1629        ),
1630        implicit_tag=ASN1_Class_KRB.AP_REP,
1631    )
1632
1633
1634class EncAPRepPart(ASN1_Packet):
1635    ASN1_codec = ASN1_Codecs.BER
1636    ASN1_root = ASN1F_SEQUENCE(
1637        ASN1F_SEQUENCE(
1638            KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA0),
1639            Microseconds("cusec", 0, explicit_tag=0xA1),
1640            ASN1F_optional(
1641                ASN1F_PACKET("subkey", None, EncryptionKey, explicit_tag=0xA2),
1642            ),
1643            ASN1F_optional(
1644                UInt32("seqNumber", 0, explicit_tag=0xA3),
1645            ),
1646        ),
1647        implicit_tag=ASN1_Class_KRB.EncAPRepPart,
1648    )
1649
1650
1651# sect 5.7
1652
1653
1654class KRB_PRIV(ASN1_Packet):
1655    ASN1_codec = ASN1_Codecs.BER
1656    ASN1_root = ASN1F_SEQUENCE(
1657        ASN1F_SEQUENCE(
1658            ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1659            ASN1F_enum_INTEGER("msgType", 21, KRB_MSG_TYPES, explicit_tag=0xA1),
1660            ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA3),
1661        ),
1662        implicit_tag=ASN1_Class_KRB.PRIV,
1663    )
1664
1665
1666class EncKrbPrivPart(ASN1_Packet):
1667    ASN1_codec = ASN1_Codecs.BER
1668    ASN1_root = ASN1F_SEQUENCE(
1669        ASN1F_SEQUENCE(
1670            ASN1F_STRING("userData", ASN1_STRING(""), explicit_tag=0xA0),
1671            ASN1F_optional(
1672                KerberosTime("timestamp", None, explicit_tag=0xA1),
1673            ),
1674            ASN1F_optional(
1675                Microseconds("usec", None, explicit_tag=0xA2),
1676            ),
1677            ASN1F_optional(
1678                UInt32("seqNumber", None, explicit_tag=0xA3),
1679            ),
1680            ASN1F_PACKET("sAddress", None, HostAddress, explicit_tag=0xA4),
1681            ASN1F_optional(
1682                ASN1F_PACKET("cAddress", None, HostAddress, explicit_tag=0xA5),
1683            ),
1684        ),
1685        implicit_tag=ASN1_Class_KRB.EncKrbPrivPart,
1686    )
1687
1688
1689# sect 5.8
1690
1691
1692class KRB_CRED(ASN1_Packet):
1693    ASN1_codec = ASN1_Codecs.BER
1694    ASN1_root = ASN1F_SEQUENCE(
1695        ASN1F_SEQUENCE(
1696            ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1697            ASN1F_enum_INTEGER("msgType", 22, KRB_MSG_TYPES, explicit_tag=0xA1),
1698            ASN1F_SEQUENCE_OF("tickets", [KRB_Ticket()], KRB_Ticket, explicit_tag=0xA2),
1699            ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA3),
1700        ),
1701        implicit_tag=ASN1_Class_KRB.CRED,
1702    )
1703
1704
1705class KrbCredInfo(ASN1_Packet):
1706    ASN1_codec = ASN1_Codecs.BER
1707    ASN1_root = ASN1F_SEQUENCE(
1708        ASN1F_PACKET("key", EncryptionKey(), EncryptionKey, explicit_tag=0xA0),
1709        ASN1F_optional(
1710            Realm("prealm", None, explicit_tag=0xA1),
1711        ),
1712        ASN1F_optional(
1713            ASN1F_PACKET("pname", None, PrincipalName, explicit_tag=0xA2),
1714        ),
1715        ASN1F_optional(
1716            KerberosFlags(
1717                "flags",
1718                None,
1719                _TICKET_FLAGS,
1720                explicit_tag=0xA3,
1721            ),
1722        ),
1723        ASN1F_optional(
1724            KerberosTime("authtime", None, explicit_tag=0xA4),
1725        ),
1726        ASN1F_optional(KerberosTime("starttime", None, explicit_tag=0xA5)),
1727        ASN1F_optional(
1728            KerberosTime("endtime", None, explicit_tag=0xA6),
1729        ),
1730        ASN1F_optional(
1731            KerberosTime("renewTill", None, explicit_tag=0xA7),
1732        ),
1733        ASN1F_optional(
1734            Realm("srealm", None, explicit_tag=0xA8),
1735        ),
1736        ASN1F_optional(
1737            ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA9),
1738        ),
1739        ASN1F_optional(
1740            HostAddresses("caddr", explicit_tag=0xAA),
1741        ),
1742    )
1743
1744
1745class EncKrbCredPart(ASN1_Packet):
1746    ASN1_codec = ASN1_Codecs.BER
1747    ASN1_root = ASN1F_SEQUENCE(
1748        ASN1F_SEQUENCE(
1749            ASN1F_SEQUENCE_OF(
1750                "ticketInfo",
1751                [KrbCredInfo()],
1752                KrbCredInfo,
1753                explicit_tag=0xA0,
1754            ),
1755            ASN1F_optional(
1756                UInt32("nonce", None, explicit_tag=0xA1),
1757            ),
1758            ASN1F_optional(
1759                KerberosTime("timestamp", None, explicit_tag=0xA2),
1760            ),
1761            ASN1F_optional(
1762                Microseconds("usec", None, explicit_tag=0xA3),
1763            ),
1764            ASN1F_optional(
1765                ASN1F_PACKET("sAddress", None, HostAddress, explicit_tag=0xA4),
1766            ),
1767            ASN1F_optional(
1768                ASN1F_PACKET("cAddress", None, HostAddress, explicit_tag=0xA5),
1769            ),
1770        ),
1771        implicit_tag=ASN1_Class_KRB.EncKrbCredPart,
1772    )
1773
1774
1775# sect 5.9.1
1776
1777
1778class MethodData(ASN1_Packet):
1779    ASN1_codec = ASN1_Codecs.BER
1780    ASN1_root = ASN1F_SEQUENCE_OF("seq", [PADATA()], PADATA)
1781
1782
1783class _KRBERROR_data_Field(ASN1F_STRING_PacketField):
1784    def m2i(self, pkt, s):
1785        val = super(_KRBERROR_data_Field, self).m2i(pkt, s)
1786        if not val[0].val:
1787            return val
1788        if pkt.errorCode.val in [14, 24, 25]:
1789            # 14: KDC_ERR_ETYPE_NOSUPP
1790            # 24: KDC_ERR_PREAUTH_FAILED
1791            # 25: KDC_ERR_PREAUTH_REQUIRED
1792            return MethodData(val[0].val, _underlayer=pkt), val[1]
1793        elif pkt.errorCode.val in [6, 7, 13, 18, 29, 41, 60]:
1794            # 6: KDC_ERR_C_PRINCIPAL_UNKNOWN
1795            # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN
1796            # 13: KDC_ERR_BADOPTION
1797            # 18: KDC_ERR_CLIENT_REVOKED
1798            # 29: KDC_ERR_SVC_UNAVAILABLE
1799            # 41: KRB_AP_ERR_MODIFIED
1800            # 60: KRB_ERR_GENERIC
1801            return KERB_ERROR_DATA(val[0].val, _underlayer=pkt), val[1]
1802        elif pkt.errorCode.val == 69:
1803            # KRB_AP_ERR_USER_TO_USER_REQUIRED
1804            return KRB_TGT_REP(val[0].val, _underlayer=pkt), val[1]
1805        return val
1806
1807
1808class KRB_ERROR(ASN1_Packet):
1809    ASN1_codec = ASN1_Codecs.BER
1810    ASN1_root = ASN1F_SEQUENCE(
1811        ASN1F_SEQUENCE(
1812            ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1813            ASN1F_enum_INTEGER("msgType", 30, KRB_MSG_TYPES, explicit_tag=0xA1),
1814            ASN1F_optional(
1815                KerberosTime("ctime", None, explicit_tag=0xA2),
1816            ),
1817            ASN1F_optional(
1818                Microseconds("cusec", None, explicit_tag=0xA3),
1819            ),
1820            KerberosTime("stime", GeneralizedTime(), explicit_tag=0xA4),
1821            Microseconds("susec", 0, explicit_tag=0xA5),
1822            ASN1F_enum_INTEGER(
1823                "errorCode",
1824                0,
1825                {
1826                    # RFC4120 sect 7.5.9
1827                    0: "KDC_ERR_NONE",
1828                    1: "KDC_ERR_NAME_EXP",
1829                    2: "KDC_ERR_SERVICE_EXP",
1830                    3: "KDC_ERR_BAD_PVNO",
1831                    4: "KDC_ERR_C_OLD_MAST_KVNO",
1832                    5: "KDC_ERR_S_OLD_MAST_KVNO",
1833                    6: "KDC_ERR_C_PRINCIPAL_UNKNOWN",
1834                    7: "KDC_ERR_S_PRINCIPAL_UNKNOWN",
1835                    8: "KDC_ERR_PRINCIPAL_NOT_UNIQUE",
1836                    9: "KDC_ERR_NULL_KEY",
1837                    10: "KDC_ERR_CANNOT_POSTDATE",
1838                    11: "KDC_ERR_NEVER_VALID",
1839                    12: "KDC_ERR_POLICY",
1840                    13: "KDC_ERR_BADOPTION",
1841                    14: "KDC_ERR_ETYPE_NOSUPP",
1842                    15: "KDC_ERR_SUMTYPE_NOSUPP",
1843                    16: "KDC_ERR_PADATA_TYPE_NOSUPP",
1844                    17: "KDC_ERR_TRTYPE_NOSUPP",
1845                    18: "KDC_ERR_CLIENT_REVOKED",
1846                    19: "KDC_ERR_SERVICE_REVOKED",
1847                    20: "KDC_ERR_TGT_REVOKED",
1848                    21: "KDC_ERR_CLIENT_NOTYET",
1849                    22: "KDC_ERR_SERVICE_NOTYET",
1850                    23: "KDC_ERR_KEY_EXPIRED",
1851                    24: "KDC_ERR_PREAUTH_FAILED",
1852                    25: "KDC_ERR_PREAUTH_REQUIRED",
1853                    26: "KDC_ERR_SERVER_NOMATCH",
1854                    27: "KDC_ERR_MUST_USE_USER2USER",
1855                    28: "KDC_ERR_PATH_NOT_ACCEPTED",
1856                    29: "KDC_ERR_SVC_UNAVAILABLE",
1857                    31: "KRB_AP_ERR_BAD_INTEGRITY",
1858                    32: "KRB_AP_ERR_TKT_EXPIRED",
1859                    33: "KRB_AP_ERR_TKT_NYV",
1860                    34: "KRB_AP_ERR_REPEAT",
1861                    35: "KRB_AP_ERR_NOT_US",
1862                    36: "KRB_AP_ERR_BADMATCH",
1863                    37: "KRB_AP_ERR_SKEW",
1864                    38: "KRB_AP_ERR_BADADDR",
1865                    39: "KRB_AP_ERR_BADVERSION",
1866                    40: "KRB_AP_ERR_MSG_TYPE",
1867                    41: "KRB_AP_ERR_MODIFIED",
1868                    42: "KRB_AP_ERR_BADORDER",
1869                    44: "KRB_AP_ERR_BADKEYVER",
1870                    45: "KRB_AP_ERR_NOKEY",
1871                    46: "KRB_AP_ERR_MUT_FAIL",
1872                    47: "KRB_AP_ERR_BADDIRECTION",
1873                    48: "KRB_AP_ERR_METHOD",
1874                    49: "KRB_AP_ERR_BADSEQ",
1875                    50: "KRB_AP_ERR_INAPP_CKSUM",
1876                    51: "KRB_AP_PATH_NOT_ACCEPTED",
1877                    52: "KRB_ERR_RESPONSE_TOO_BIG",
1878                    60: "KRB_ERR_GENERIC",
1879                    61: "KRB_ERR_FIELD_TOOLONG",
1880                    62: "KDC_ERROR_CLIENT_NOT_TRUSTED",
1881                    63: "KDC_ERROR_KDC_NOT_TRUSTED",
1882                    64: "KDC_ERROR_INVALID_SIG",
1883                    65: "KDC_ERR_KEY_TOO_WEAK",
1884                    66: "KDC_ERR_CERTIFICATE_MISMATCH",
1885                    67: "KRB_AP_ERR_NO_TGT",
1886                    68: "KDC_ERR_WRONG_REALM",
1887                    69: "KRB_AP_ERR_USER_TO_USER_REQUIRED",
1888                    70: "KDC_ERR_CANT_VERIFY_CERTIFICATE",
1889                    71: "KDC_ERR_INVALID_CERTIFICATE",
1890                    72: "KDC_ERR_REVOKED_CERTIFICATE",
1891                    73: "KDC_ERR_REVOCATION_STATUS_UNKNOWN",
1892                    74: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE",
1893                    75: "KDC_ERR_CLIENT_NAME_MISMATCH",
1894                    76: "KDC_ERR_KDC_NAME_MISMATCH",
1895                    # draft-ietf-kitten-iakerb
1896                    85: "KRB_AP_ERR_IAKERB_KDC_NOT_FOUND",
1897                    86: "KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE",
1898                    # RFC6113
1899                    90: "KDC_ERR_PREAUTH_EXPIRED",
1900                    91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED",
1901                    92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET",
1902                    93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS",
1903                },
1904                explicit_tag=0xA6,
1905            ),
1906            ASN1F_optional(Realm("crealm", None, explicit_tag=0xA7)),
1907            ASN1F_optional(
1908                ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA8),
1909            ),
1910            Realm("realm", "", explicit_tag=0xA9),
1911            ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xAA),
1912            ASN1F_optional(KerberosString("eText", "", explicit_tag=0xAB)),
1913            ASN1F_optional(_KRBERROR_data_Field("eData", "", explicit_tag=0xAC)),
1914        ),
1915        implicit_tag=ASN1_Class_KRB.ERROR,
1916    )
1917
1918
1919# [MS-KILE] sect 2.2.1
1920
1921
1922class KERB_EXT_ERROR(Packet):
1923    fields_desc = [
1924        XLEIntField("status", 0),
1925        XLEIntField("reserved", 0),
1926        XLEIntField("flags", 0x00000001),
1927    ]
1928
1929
1930# [MS-KILE] sect 2.2.2
1931
1932
1933class _Error_Field(ASN1F_STRING_PacketField):
1934    def m2i(self, pkt, s):
1935        val = super(_Error_Field, self).m2i(pkt, s)
1936        if not val[0].val:
1937            return val
1938        if pkt.dataType.val == 3:  # KERB_ERR_TYPE_EXTENDED
1939            return KERB_EXT_ERROR(val[0].val, _underlayer=pkt), val[1]
1940        return val
1941
1942
1943class KERB_ERROR_DATA(ASN1_Packet):
1944    ASN1_codec = ASN1_Codecs.BER
1945    ASN1_root = ASN1F_SEQUENCE(
1946        ASN1F_enum_INTEGER(
1947            "dataType",
1948            2,
1949            {
1950                1: "KERB_AP_ERR_TYPE_NTSTATUS",  # from the wdk
1951                2: "KERB_AP_ERR_TYPE_SKEW_RECOVERY",
1952                3: "KERB_ERR_TYPE_EXTENDED",
1953            },
1954            explicit_tag=0xA1,
1955        ),
1956        ASN1F_optional(_Error_Field("dataValue", None, explicit_tag=0xA2)),
1957    )
1958
1959
1960# Kerberos U2U - draft-ietf-cat-user2user-03
1961
1962
1963class KRB_TGT_REQ(ASN1_Packet):
1964    ASN1_codec = ASN1_Codecs.BER
1965    ASN1_root = ASN1F_SEQUENCE(
1966        ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1967        ASN1F_enum_INTEGER("msgType", 16, KRB_MSG_TYPES, explicit_tag=0xA1),
1968        ASN1F_optional(
1969            ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA2),
1970        ),
1971        ASN1F_optional(
1972            Realm("realm", None, explicit_tag=0xA3),
1973        ),
1974    )
1975
1976
1977class KRB_TGT_REP(ASN1_Packet):
1978    ASN1_codec = ASN1_Codecs.BER
1979    ASN1_root = ASN1F_SEQUENCE(
1980        ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0),
1981        ASN1F_enum_INTEGER("msgType", 17, KRB_MSG_TYPES, explicit_tag=0xA1),
1982        ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA2),
1983    )
1984
1985
1986# draft-ietf-kitten-iakerb-03 sect 4
1987
1988
1989class KRB_FINISHED(ASN1_Packet):
1990    ASN1_codec = ASN1_Codecs.BER
1991    ASN1_root = ASN1F_SEQUENCE(
1992        ASN1F_PACKET("gssMic", Checksum(), Checksum, explicit_tag=0xA1),
1993    )
1994
1995
1996# RFC 6542 sect 3.1
1997
1998
1999class KRB_GSS_EXT(Packet):
2000    fields_desc = [
2001        IntEnumField(
2002            "type",
2003            0,
2004            {
2005                # https://www.iana.org/assignments/kerberos-v-gss-api/kerberos-v-gss-api.xhtml
2006                0x00000000: "GSS_EXTS_CHANNEL_BINDING",  # RFC 6542 sect 3.2
2007                0x00000001: "GSS_EXTS_IAKERB_FINISHED",  # not standard
2008                0x00000002: "GSS_EXTS_FINISHED",  # PKU2U / IAKERB
2009            },
2010        ),
2011        FieldLenField("length", None, length_of="data", fmt="!I"),
2012        MultipleTypeField(
2013            [
2014                (
2015                    PacketField("data", KRB_FINISHED(), KRB_FINISHED),
2016                    lambda pkt: pkt.type == 0x00000002,
2017                ),
2018            ],
2019            XStrLenField("data", b"", length_from=lambda pkt: pkt.length),
2020        ),
2021    ]
2022
2023
2024# RFC 4121 sect 4.1.1
2025
2026
2027class KRB_AuthenticatorChecksum(Packet):
2028    fields_desc = [
2029        FieldLenField("Lgth", None, length_of="Bnd", fmt="<I"),
2030        PacketLenField(
2031            "Bnd",
2032            GssChannelBindings(),
2033            GssChannelBindings,
2034            length_from=lambda pkt: pkt.Lgth,
2035        ),
2036        FlagsField(
2037            "Flags",
2038            0,
2039            -32,
2040            {
2041                0x01: "GSS_C_DELEG_FLAG",
2042                0x02: "GSS_C_MUTUAL_FLAG",
2043                0x04: "GSS_C_REPLAY_FLAG",
2044                0x08: "GSS_C_SEQUENCE_FLAG",
2045                0x10: "GSS_C_CONF_FLAG",  # confidentiality
2046                0x20: "GSS_C_INTEG_FLAG",  # integrity
2047                # RFC4757
2048                0x1000: "GSS_C_DCE_STYLE",
2049                0x2000: "GSS_C_IDENTIFY_FLAG",
2050                0x4000: "GSS_C_EXTENDED_ERROR_FLAG",
2051            },
2052        ),
2053        ConditionalField(
2054            LEShortField("DlgOpt", 0),
2055            lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG,
2056        ),
2057        ConditionalField(
2058            FieldLenField("Dlgth", None, length_of="Deleg"),
2059            lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG,
2060        ),
2061        ConditionalField(
2062            PacketLenField(
2063                "Deleg", KRB_CRED(), KRB_CRED, length_from=lambda pkt: pkt.Dlgth
2064            ),
2065            lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG,
2066        ),
2067        # Extensions: RFC 6542 sect 3.1
2068        PacketListField("Exts", KRB_GSS_EXT(), KRB_GSS_EXT),
2069    ]
2070
2071
2072# Kerberos V5 GSS-API - RFC1964 and RFC4121
2073
2074_TOK_IDS = {
2075    # RFC 1964
2076    b"\x01\x00": "KRB-AP-REQ",
2077    b"\x02\x00": "KRB-AP-REP",
2078    b"\x03\x00": "KRB-ERROR",
2079    b"\x01\x01": "GSS_GetMIC-RFC1964",
2080    b"\x02\x01": "GSS_Wrap-RFC1964",
2081    b"\x01\x02": "GSS_Delete_sec_context-RFC1964",
2082    # U2U: [draft-ietf-cat-user2user-03]
2083    b"\x04\x00": "KRB-TGT-REQ",
2084    b"\x04\x01": "KRB-TGT-REP",
2085    # RFC 4121
2086    b"\x04\x04": "GSS_GetMIC",
2087    b"\x05\x04": "GSS_Wrap",
2088    # IAKERB: [draft-ietf-kitten-iakerb-03]
2089    b"\x05\x01": "IAKERB_PROXY",
2090}
2091_SGN_ALGS = {
2092    0x00: "DES MAC MD5",
2093    0x01: "MD2.5",
2094    0x02: "DES MAC",
2095    # RFC 4757
2096    0x11: "HMAC",
2097}
2098_SEAL_ALGS = {
2099    0: "DES",
2100    0xFFFF: "none",
2101    # RFC 4757
2102    0x10: "RC4",
2103}
2104
2105
2106# RFC 1964 - sect 1.1
2107
2108# See https://www.iana.org/assignments/kerberos-v-gss-api/kerberos-v-gss-api.xhtml
2109_InitialContextTokens = {}  # filled below
2110
2111
2112class KRB_InnerToken(Packet):
2113    name = "Kerberos v5 InnerToken"
2114    fields_desc = [
2115        StrFixedLenEnumField("TOK_ID", b"\x01\x00", _TOK_IDS, length=2),
2116        PacketField(
2117            "root",
2118            KRB_AP_REQ(),
2119            lambda x, _parent: _InitialContextTokens[_parent.TOK_ID](x),
2120        ),
2121    ]
2122
2123    def mysummary(self):
2124        return self.sprintf(
2125            "Kerberos %s" % _TOK_IDS.get(self.TOK_ID, repr(self.TOK_ID))
2126        )
2127
2128    def guess_payload_class(self, payload):
2129        if self.TOK_ID in [b"\x01\x01", b"\x02\x01", b"\x04\x04", b"\x05\x04"]:
2130            return conf.padding_layer
2131        return Kerberos
2132
2133    @classmethod
2134    def dispatch_hook(cls, _pkt=None, *args, **kargs):
2135        if _pkt and len(_pkt) >= 13:
2136            # Older RFC1964 variants of the token have KRB_GSSAPI_Token wrapper
2137            if _pkt[2:13] == b"\x06\t*\x86H\x86\xf7\x12\x01\x02\x02":
2138                return KRB_GSSAPI_Token
2139        return cls
2140
2141
2142# RFC 4121 - sect 4.1
2143
2144
2145class KRB_GSSAPI_Token(GSSAPI_BLOB):
2146    name = "Kerberos GSSAPI-Token"
2147    ASN1_codec = ASN1_Codecs.BER
2148    ASN1_root = ASN1F_SEQUENCE(
2149        ASN1F_OID("MechType", "1.2.840.113554.1.2.2"),
2150        ASN1F_PACKET(
2151            "innerToken",
2152            KRB_InnerToken(),
2153            KRB_InnerToken,
2154            implicit_tag=0x0,
2155        ),
2156        implicit_tag=ASN1_Class_KRB.Token,
2157    )
2158
2159
2160# RFC 1964 - sect 1.2.1
2161
2162
2163class KRB_GSS_MIC_RFC1964(Packet):
2164    name = "Kerberos v5 MIC Token (RFC1964)"
2165    fields_desc = [
2166        LEShortEnumField("SGN_ALG", 0, _SGN_ALGS),
2167        XLEIntField("Filler", 0xFFFFFFFF),
2168        XStrFixedLenField("SND_SEQ", b"", length=8),
2169        PadField(  # sect 1.2.2.3
2170            XStrFixedLenField("SGN_CKSUM", b"", length=8),
2171            align=8,
2172            padwith=b"\x04",
2173        ),
2174    ]
2175
2176    def default_payload_class(self, payload):
2177        return conf.padding_layer
2178
2179
2180_InitialContextTokens[b"\x01\x01"] = KRB_GSS_MIC_RFC1964
2181
2182# RFC 1964 - sect 1.2.2
2183
2184
2185class KRB_GSS_Wrap_RFC1964(Packet):
2186    name = "Kerberos v5 GSS_Wrap (RFC1964)"
2187    fields_desc = [
2188        LEShortEnumField("SGN_ALG", 0, _SGN_ALGS),
2189        LEShortEnumField("SEAL_ALG", 0, _SEAL_ALGS),
2190        XLEShortField("Filler", 0xFFFF),
2191        XStrFixedLenField("SND_SEQ", b"", length=8),
2192        PadField(  # sect 1.2.2.3
2193            XStrFixedLenField("SGN_CKSUM", b"", length=8),
2194            align=8,
2195            padwith=b"\x04",
2196        ),
2197        # sect 1.2.2.3
2198        XStrFixedLenField("CONFOUNDER", b"", length=8),
2199    ]
2200
2201    def default_payload_class(self, payload):
2202        return conf.padding_layer
2203
2204
2205_InitialContextTokens[b"\x02\x01"] = KRB_GSS_Wrap_RFC1964
2206
2207
2208# RFC 1964 - sect 1.2.2
2209
2210
2211class KRB_GSS_Delete_sec_context_RFC1964(Packet):
2212    name = "Kerberos v5 GSS_Delete_sec_context (RFC1964)"
2213    fields_desc = KRB_GSS_MIC_RFC1964.fields_desc
2214
2215
2216_InitialContextTokens[b"\x01\x02"] = KRB_GSS_Delete_sec_context_RFC1964
2217
2218
2219# RFC 4121 - sect 4.2.2
2220_KRB5_GSS_Flags = [
2221    "SentByAcceptor",
2222    "Sealed",
2223    "AcceptorSubkey",
2224]
2225
2226
2227# RFC 4121 - sect 4.2.6.1
2228
2229
2230class KRB_GSS_MIC(Packet):
2231    name = "Kerberos v5 MIC Token"
2232    fields_desc = [
2233        FlagsField("Flags", 0, 8, _KRB5_GSS_Flags),
2234        XStrFixedLenField("Filler", b"\xff\xff\xff\xff\xff", length=5),
2235        LongField("SND_SEQ", 0),  # Big endian
2236        XStrField("SGN_CKSUM", b"\x00" * 12),
2237    ]
2238
2239    def default_payload_class(self, payload):
2240        return conf.padding_layer
2241
2242
2243_InitialContextTokens[b"\x04\x04"] = KRB_GSS_MIC
2244
2245
2246# RFC 4121 - sect 4.2.6.2
2247
2248
2249class KRB_GSS_Wrap(Packet):
2250    name = "Kerberos v5 Wrap Token"
2251    fields_desc = [
2252        FlagsField("Flags", 0, 8, _KRB5_GSS_Flags),
2253        XByteField("Filler", 0xFF),
2254        ShortField("EC", 0),  # Big endian
2255        ShortField("RRC", 0),  # Big endian
2256        LongField("SND_SEQ", 0),  # Big endian
2257        MultipleTypeField(
2258            [
2259                (
2260                    XStrField("Data", b""),
2261                    lambda pkt: pkt.Flags.Sealed,
2262                )
2263            ],
2264            XStrLenField("Data", b"", length_from=lambda pkt: pkt.EC),
2265        ),
2266    ]
2267
2268    def default_payload_class(self, payload):
2269        return conf.padding_layer
2270
2271
2272_InitialContextTokens[b"\x05\x04"] = KRB_GSS_Wrap
2273
2274
2275# Kerberos IAKERB - draft-ietf-kitten-iakerb-03
2276
2277
2278class IAKERB_HEADER(ASN1_Packet):
2279    ASN1_codec = ASN1_Codecs.BER
2280    ASN1_root = ASN1F_SEQUENCE(
2281        Realm("targetRealm", "", explicit_tag=0xA1),
2282        ASN1F_optional(
2283            ASN1F_STRING("cookie", None, explicit_tag=0xA2),
2284        ),
2285    )
2286
2287
2288_InitialContextTokens[b"\x05\x01"] = IAKERB_HEADER
2289
2290
2291# Register for GSSAPI
2292
2293# Kerberos 5
2294_GSSAPI_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken
2295_GSSAPI_SIGNATURE_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken
2296# Kerberos 5 - U2U
2297_GSSAPI_OIDS["1.2.840.113554.1.2.2.3"] = KRB_InnerToken
2298# Kerberos 5 - IAKERB
2299_GSSAPI_OIDS["1.3.6.1.5.2.5"] = KRB_InnerToken
2300
2301
2302# Entry class
2303
2304# RFC4120 sect 5.10
2305
2306
2307class Kerberos(ASN1_Packet):
2308    ASN1_codec = ASN1_Codecs.BER
2309    ASN1_root = ASN1F_CHOICE(
2310        "root",
2311        None,
2312        # RFC4120
2313        KRB_GSSAPI_Token,  # [APPLICATION 0]
2314        KRB_Ticket,  # [APPLICATION 1]
2315        KRB_Authenticator,  # [APPLICATION 2]
2316        KRB_AS_REQ,  # [APPLICATION 10]
2317        KRB_AS_REP,  # [APPLICATION 11]
2318        KRB_TGS_REQ,  # [APPLICATION 12]
2319        KRB_TGS_REP,  # [APPLICATION 13]
2320        KRB_AP_REQ,  # [APPLICATION 14]
2321        KRB_AP_REP,  # [APPLICATION 15]
2322        # RFC4120
2323        KRB_ERROR,  # [APPLICATION 30]
2324    )
2325
2326    def mysummary(self):
2327        return self.root.summary()
2328
2329
2330bind_bottom_up(UDP, Kerberos, sport=88)
2331bind_bottom_up(UDP, Kerberos, dport=88)
2332bind_layers(UDP, Kerberos, sport=88, dport=88)
2333
2334_InitialContextTokens[b"\x01\x00"] = KRB_AP_REQ
2335_InitialContextTokens[b"\x02\x00"] = KRB_AP_REP
2336_InitialContextTokens[b"\x03\x00"] = KRB_ERROR
2337_InitialContextTokens[b"\x04\x00"] = KRB_TGT_REQ
2338_InitialContextTokens[b"\x04\x01"] = KRB_TGT_REP
2339
2340
2341# RFC4120 sect 7.2.2
2342
2343
2344class KerberosTCPHeader(Packet):
2345    # According to RFC 5021, first bit to 1 has a special meaning and
2346    # negotiates Kerberos TCP extensions... But apart from rfc6251 no one used that
2347    # https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-4
2348    fields_desc = [LenField("len", None, fmt="!I")]
2349
2350    @classmethod
2351    def tcp_reassemble(cls, data, *args, **kwargs):
2352        if len(data) < 4:
2353            return None
2354        length = struct.unpack("!I", data[:4])[0]
2355        if len(data) == length + 4:
2356            return cls(data)
2357
2358
2359bind_layers(KerberosTCPHeader, Kerberos)
2360
2361bind_bottom_up(TCP, KerberosTCPHeader, sport=88)
2362bind_layers(TCP, KerberosTCPHeader, dport=88)
2363
2364
2365# RFC3244 sect 2
2366
2367
2368class KPASSWD_REQ(Packet):
2369    fields_desc = [
2370        ShortField("len", None),
2371        ShortField("pvno", 0xFF80),
2372        ShortField("apreqlen", None),
2373        PacketLenField(
2374            "apreq", KRB_AP_REQ(), KRB_AP_REQ, length_from=lambda pkt: pkt.apreqlen
2375        ),
2376        ConditionalField(
2377            PacketLenField(
2378                "krbpriv",
2379                KRB_PRIV(),
2380                KRB_PRIV,
2381                length_from=lambda pkt: pkt.len - 6 - pkt.apreqlen,
2382            ),
2383            lambda pkt: pkt.apreqlen != 0,
2384        ),
2385        ConditionalField(
2386            PacketLenField(
2387                "error", KRB_ERROR(), KRB_ERROR, length_from=lambda pkt: pkt.len - 6
2388            ),
2389            lambda pkt: pkt.apreqlen == 0,
2390        ),
2391    ]
2392
2393    def post_build(self, p, pay):
2394        if self.len is None:
2395            p = struct.pack("!H", len(p)) + p[2:]
2396        if self.apreqlen is None and self.krbpriv is not None:
2397            p = p[:4] + struct.pack("!H", len(self.apreq)) + p[6:]
2398        return p + pay
2399
2400
2401class ChangePasswdData(ASN1_Packet):
2402    ASN1_codec = ASN1_Codecs.BER
2403    ASN1_root = ASN1F_SEQUENCE(
2404        ASN1F_STRING("newpasswd", ASN1_STRING(""), explicit_tag=0xA0),
2405        ASN1F_optional(
2406            ASN1F_PACKET("targname", None, PrincipalName, explicit_tag=0xA1)
2407        ),
2408        ASN1F_optional(Realm("targrealm", None, explicit_tag=0xA2)),
2409    )
2410
2411
2412class KPASSWD_REP(Packet):
2413    fields_desc = [
2414        ShortField("len", None),
2415        ShortField("pvno", 0x0001),
2416        ShortField("apreplen", None),
2417        PacketLenField(
2418            "aprep", KRB_AP_REP(), KRB_AP_REP, length_from=lambda pkt: pkt.apreplen
2419        ),
2420        ConditionalField(
2421            PacketLenField(
2422                "krbpriv",
2423                KRB_PRIV(),
2424                KRB_PRIV,
2425                length_from=lambda pkt: pkt.len - 6 - pkt.apreplen,
2426            ),
2427            lambda pkt: pkt.apreplen != 0,
2428        ),
2429        ConditionalField(
2430            PacketLenField(
2431                "error", KRB_ERROR(), KRB_ERROR, length_from=lambda pkt: pkt.len - 6
2432            ),
2433            lambda pkt: pkt.apreplen == 0,
2434        ),
2435    ]
2436
2437    def post_build(self, p, pay):
2438        if self.len is None:
2439            p = struct.pack("!H", len(p)) + p[2:]
2440        if self.apreplen is None and self.krbpriv is not None:
2441            p = p[:4] + struct.pack("!H", len(self.aprep)) + p[6:]
2442        return p + pay
2443
2444    def answers(self, other):
2445        return isinstance(other, KPASSWD_REQ)
2446
2447
2448KPASSWD_RESULTS = {
2449    0: "KRB5_KPASSWD_SUCCESS",
2450    1: "KRB5_KPASSWD_MALFORMED",
2451    2: "KRB5_KPASSWD_HARDERROR",
2452    3: "KRB5_KPASSWD_AUTHERROR",
2453    4: "KRB5_KPASSWD_SOFTERROR",
2454    5: "KRB5_KPASSWD_ACCESSDENIED",
2455    6: "KRB5_KPASSWD_BAD_VERSION",
2456    7: "KRB5_KPASSWD_INITIAL_FLAG_NEEDED",
2457}
2458
2459
2460class KPasswdRepData(Packet):
2461    fields_desc = [
2462        ShortEnumField("resultCode", 0, KPASSWD_RESULTS),
2463        StrField("resultString", ""),
2464    ]
2465
2466
2467class Kpasswd(Packet):
2468    @classmethod
2469    def dispatch_hook(cls, _pkt=None, *args, **kargs):
2470        if _pkt and len(_pkt) >= 4:
2471            if _pkt[2:4] == b"\xff\x80":
2472                return KPASSWD_REQ
2473            elif _pkt[2:4] == b"\x00\x01":
2474                asn1_tag = BER_id_dec(_pkt[6:8])[0] & 0x1F
2475                if asn1_tag == 14:
2476                    return KPASSWD_REQ
2477                elif asn1_tag == 15:
2478                    return KPASSWD_REP
2479        return KPASSWD_REQ
2480
2481
2482bind_bottom_up(UDP, Kpasswd, sport=464)
2483bind_bottom_up(UDP, Kpasswd, dport=464)
2484bind_top_down(UDP, KPASSWD_REQ, sport=464, dport=464)
2485bind_top_down(UDP, KPASSWD_REP, sport=464, dport=464)
2486
2487
2488class KpasswdTCPHeader(Packet):
2489    fields_desc = [LenField("len", None, fmt="!I")]
2490
2491    @classmethod
2492    def tcp_reassemble(cls, data, *args, **kwargs):
2493        if len(data) < 4:
2494            return None
2495        length = struct.unpack("!I", data[:4])[0]
2496        if len(data) == length + 4:
2497            return cls(data)
2498
2499
2500bind_layers(KpasswdTCPHeader, Kpasswd)
2501
2502bind_bottom_up(TCP, KpasswdTCPHeader, sport=464)
2503bind_layers(TCP, KpasswdTCPHeader, dport=464)
2504
2505
2506# Util functions
2507
2508
2509class KerberosClient(Automaton):
2510    RES_AS_MODE = namedtuple("AS_Result", ["asrep", "sessionkey", "kdcrep"])
2511    RES_TGS_MODE = namedtuple("TGS_Result", ["tgsrep", "sessionkey", "kdcrep"])
2512
2513    class MODE(IntEnum):
2514        AS_REQ = 0
2515        TGS_REQ = 1
2516        GET_SALT = 2
2517
2518    def __init__(
2519        self,
2520        mode=MODE.AS_REQ,
2521        ip=None,
2522        host=None,
2523        upn=None,
2524        password=None,
2525        realm=None,
2526        spn=None,
2527        ticket=None,
2528        renew=False,
2529        additional_tickets=[],
2530        u2u=False,
2531        for_user=None,
2532        s4u2proxy=False,
2533        etypes=None,
2534        key=None,
2535        port=88,
2536        timeout=5,
2537        **kwargs,
2538    ):
2539        import scapy.libs.rfc3961  # Trigger error if any  # noqa: F401
2540        from scapy.layers.ldap import dclocator
2541
2542        if not upn:
2543            raise ValueError("Invalid upn")
2544        if not spn:
2545            raise ValueError("Invalid spn")
2546        if realm is None:
2547            if mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]:
2548                _, realm = _parse_upn(upn)
2549            elif mode == self.MODE.TGS_REQ:
2550                _, realm = _parse_spn(spn)
2551                if not realm and ticket:
2552                    # if no realm is specified, but there's a ticket, take the realm
2553                    # of the ticket.
2554                    realm = ticket.realm.val.decode()
2555            else:
2556                raise ValueError("Invalid realm")
2557
2558        if mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]:
2559            if not host:
2560                raise ValueError("Invalid host")
2561        elif mode == self.MODE.TGS_REQ:
2562            if not ticket:
2563                raise ValueError("Invalid ticket")
2564
2565        if not ip:
2566            # No KDC IP provided. Find it by querying the DNS
2567            ip = dclocator(
2568                realm,
2569                timeout=timeout,
2570                # Use connect mode instead of ldap for compatibility
2571                # with MIT kerberos servers
2572                mode="connect",
2573                port=port,
2574                debug=kwargs.get("debug", 0),
2575            ).ip
2576
2577        if mode == self.MODE.GET_SALT:
2578            if etypes is not None:
2579                raise ValueError("Cannot specify etypes in GET_SALT mode !")
2580
2581            from scapy.libs.rfc3961 import EncryptionType
2582
2583            etypes = [
2584                EncryptionType.AES256_CTS_HMAC_SHA1_96,
2585                EncryptionType.AES128_CTS_HMAC_SHA1_96,
2586            ]
2587        elif etypes is None:
2588            from scapy.libs.rfc3961 import EncryptionType
2589
2590            etypes = [
2591                EncryptionType.AES256_CTS_HMAC_SHA1_96,
2592                EncryptionType.AES128_CTS_HMAC_SHA1_96,
2593                EncryptionType.RC4_HMAC,
2594                EncryptionType.DES_CBC_MD5,
2595            ]
2596        self.etypes = etypes
2597
2598        self.mode = mode
2599
2600        self.result = None  # Result
2601
2602        self._timeout = timeout
2603        self._ip = ip
2604        self._port = port
2605        sock = self._connect()
2606
2607        if self.mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]:
2608            self.host = host.upper()
2609            self.password = password and bytes_encode(password)
2610        self.spn = spn
2611        self.upn = upn
2612        self.realm = realm.upper()
2613        self.ticket = ticket
2614        self.renew = renew
2615        self.additional_tickets = additional_tickets  # U2U + S4U2Proxy
2616        self.u2u = u2u  # U2U
2617        self.for_user = for_user  # FOR-USER
2618        self.s4u2proxy = s4u2proxy  # S4U2Proxy
2619        self.key = key
2620        # See RFC4120 - sect 7.2.2
2621        # This marks whether we should follow-up after an EOF
2622        self.should_followup = False
2623        # Negotiated parameters
2624        self.pre_auth = False
2625        self.fxcookie = None
2626        super(KerberosClient, self).__init__(
2627            sock=sock,
2628            **kwargs,
2629        )
2630
2631    def _connect(self):
2632        sock = socket.socket()
2633        sock.settimeout(self._timeout)
2634        sock.connect((self._ip, self._port))
2635        sock = StreamSocket(sock, KerberosTCPHeader)
2636        return sock
2637
2638    def send(self, pkt):
2639        super(KerberosClient, self).send(KerberosTCPHeader() / pkt)
2640
2641    def _base_kdc_req(self, now_time):
2642        kdcreq = KRB_KDC_REQ_BODY(
2643            etype=[ASN1_INTEGER(x) for x in self.etypes],
2644            additionalTickets=None,
2645            # Windows default
2646            kdcOptions="forwardable+renewable+canonicalize",
2647            cname=None,
2648            realm=ASN1_GENERAL_STRING(self.realm),
2649            till=ASN1_GENERALIZED_TIME(now_time + timedelta(hours=10)),
2650            rtime=ASN1_GENERALIZED_TIME(now_time + timedelta(hours=10)),
2651            nonce=ASN1_INTEGER(RandNum(0, 0x7FFFFFFF)._fix()),
2652        )
2653        if self.renew:
2654            kdcreq.kdcOptions.set(30, 1)  # set 'renew' (bit 30)
2655        return kdcreq
2656
2657    def as_req(self):
2658        now_time = datetime.now(timezone.utc).replace(microsecond=0)
2659
2660        kdc_req = self._base_kdc_req(now_time=now_time)
2661        kdc_req.addresses = [
2662            HostAddress(
2663                addrType=ASN1_INTEGER(20),  # Netbios
2664                address=ASN1_STRING(self.host.ljust(16, " ")),
2665            )
2666        ]
2667        kdc_req.cname = PrincipalName.fromUPN(self.upn)
2668        kdc_req.sname = PrincipalName.fromSPN(self.spn)
2669
2670        asreq = Kerberos(
2671            root=KRB_AS_REQ(
2672                padata=[
2673                    PADATA(
2674                        padataType=ASN1_INTEGER(128),  # PA-PAC-REQUEST
2675                        padataValue=PA_PAC_REQUEST(includePac=ASN1_BOOLEAN(-1)),
2676                    )
2677                ],
2678                reqBody=kdc_req,
2679            )
2680        )
2681        # Pre-auth support
2682        if self.pre_auth:
2683            asreq.root.padata.insert(
2684                0,
2685                PADATA(
2686                    padataType=0x2,  # PA-ENC-TIMESTAMP
2687                    padataValue=EncryptedData(),
2688                ),
2689            )
2690            asreq.root.padata[0].padataValue.encrypt(
2691                self.key, PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time))
2692            )
2693        # Cookie support
2694        if self.fxcookie:
2695            asreq.root.padata.insert(
2696                0,
2697                PADATA(
2698                    padataType=133,  # PA-FX-COOKIE
2699                    padataValue=self.fxcookie,
2700                ),
2701            )
2702        return asreq
2703
2704    def tgs_req(self):
2705        now_time = datetime.now(timezone.utc).replace(microsecond=0)
2706
2707        kdc_req = self._base_kdc_req(now_time=now_time)
2708
2709        _, crealm = _parse_upn(self.upn)
2710        authenticator = KRB_Authenticator(
2711            crealm=ASN1_GENERAL_STRING(crealm),
2712            cname=PrincipalName.fromUPN(self.upn),
2713            cksum=None,
2714            ctime=ASN1_GENERALIZED_TIME(now_time),
2715            cusec=ASN1_INTEGER(0),
2716            subkey=None,
2717            seqNumber=None,
2718            encAuthorizationData=None,
2719        )
2720
2721        apreq = KRB_AP_REQ(ticket=self.ticket, authenticator=EncryptedData())
2722
2723        # Additional tickets
2724        if self.additional_tickets:
2725            kdc_req.additionalTickets = self.additional_tickets
2726
2727        if self.u2u:  # U2U
2728            kdc_req.kdcOptions.set(28, 1)  # set 'enc-tkt-in-skey' (bit 28)
2729
2730        kdc_req.sname = PrincipalName.fromSPN(self.spn)
2731
2732        tgsreq = Kerberos(
2733            root=KRB_TGS_REQ(
2734                padata=[
2735                    PADATA(
2736                        padataType=ASN1_INTEGER(1),  # PA-TGS-REQ
2737                        padataValue=apreq,
2738                    )
2739                ],
2740                reqBody=kdc_req,
2741            )
2742        )
2743
2744        # [MS-SFU] FOR-USER extension
2745        if self.for_user is not None:
2746            from scapy.libs.rfc3961 import ChecksumType
2747
2748            paforuser = PA_FOR_USER(
2749                userName=PrincipalName.fromUPN(self.for_user),
2750                userRealm=ASN1_GENERAL_STRING(_parse_upn(self.for_user)[1]),
2751                cksum=Checksum(),
2752            )
2753            S4UByteArray = struct.pack(  # [MS-SFU] sect 2.2.1
2754                "<I", paforuser.userName.nameType.val
2755            ) + (
2756                (
2757                    "".join(x.val for x in paforuser.userName.nameString)
2758                    + paforuser.userRealm.val
2759                    + paforuser.authPackage.val
2760                ).encode()
2761            )
2762            paforuser.cksum.make(
2763                self.key,
2764                S4UByteArray,
2765                cksumtype=ChecksumType.HMAC_MD5,
2766            )
2767            tgsreq.root.padata.append(
2768                PADATA(
2769                    padataType=ASN1_INTEGER(129),  # PA-FOR-USER
2770                    padataValue=paforuser,
2771                )
2772            )
2773
2774        # [MS-SFU] S4U2proxy - sect 3.1.5.2.1
2775        if self.s4u2proxy:
2776            # "PA-PAC-OPTIONS with resource-based constrained-delegation bit set"
2777            tgsreq.root.padata.append(
2778                PADATA(
2779                    padataType=ASN1_INTEGER(167),  # PA-PAC-OPTIONS
2780                    padataValue=PA_PAC_OPTIONS(
2781                        options="Resource-based-constrained-delegation",
2782                    ),
2783                )
2784            )
2785            # "kdc-options field: MUST include the new cname-in-addl-tkt options flag"
2786            kdc_req.kdcOptions.set(14, 1)
2787
2788        # Compute checksum
2789        if self.key.cksumtype:
2790            authenticator.cksum = Checksum()
2791            authenticator.cksum.make(
2792                self.key,
2793                bytes(kdc_req),
2794            )
2795        # Encrypt authenticator
2796        apreq.authenticator.encrypt(self.key, authenticator)
2797        return tgsreq
2798
2799    @ATMT.state(initial=1)
2800    def BEGIN(self):
2801        pass
2802
2803    @ATMT.condition(BEGIN)
2804    def should_send_as_req(self):
2805        if self.mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]:
2806            raise self.SENT_AP_REQ()
2807
2808    @ATMT.condition(BEGIN)
2809    def should_send_tgs_req(self):
2810        if self.mode == self.MODE.TGS_REQ:
2811            raise self.SENT_TGS_REQ()
2812
2813    @ATMT.action(should_send_as_req)
2814    def send_as_req(self):
2815        self.send(self.as_req())
2816
2817    @ATMT.action(should_send_tgs_req)
2818    def send_tgs_req(self):
2819        self.send(self.tgs_req())
2820
2821    @ATMT.state()
2822    def SENT_AP_REQ(self):
2823        pass
2824
2825    @ATMT.state()
2826    def SENT_TGS_REQ(self):
2827        pass
2828
2829    def _process_padatas_and_key(self, padatas):
2830        from scapy.libs.rfc3961 import EncryptionType, Key
2831
2832        etype = None
2833        salt = b""
2834        # Process pa-data
2835        if padatas is not None:
2836            for padata in padatas:
2837                if padata.padataType == 0x13 and etype is None:  # PA-ETYPE-INFO2
2838                    elt = padata.padataValue.seq[0]
2839                    if elt.etype.val in self.etypes:
2840                        etype = elt.etype.val
2841                        if etype != EncryptionType.RC4_HMAC:
2842                            salt = elt.salt.val
2843                elif padata.padataType == 133:  # PA-FX-COOKIE
2844                    self.fxcookie = padata.padataValue
2845
2846        etype = etype or self.etypes[0]
2847        # Compute key if not already provided
2848        if self.key is None:
2849            self.key = Key.string_to_key(
2850                etype,
2851                self.password,
2852                salt,
2853            )
2854
2855    @ATMT.receive_condition(SENT_AP_REQ, prio=0)
2856    def receive_salt_mode(self, pkt):
2857        # This is only for "Salt-Mode", a mode where we get the salt then
2858        # exit.
2859        if self.mode == self.MODE.GET_SALT:
2860            if Kerberos not in pkt:
2861                raise self.FINAL()
2862            if not isinstance(pkt.root, KRB_ERROR):
2863                log_runtime.error("Pre-auth is likely disabled !")
2864                raise self.FINAL()
2865            if pkt.root.errorCode == 25:  # KDC_ERR_PREAUTH_REQUIRED
2866                for padata in pkt.root.eData.seq:
2867                    if padata.padataType == 0x13:  # PA-ETYPE-INFO2
2868                        elt = padata.padataValue.seq[0]
2869                        if elt.etype.val in self.etypes:
2870                            self.result = elt.salt.val
2871                            raise self.FINAL()
2872            else:
2873                log_runtime.error("Failed to retrieve the salt !")
2874                raise self.FINAL()
2875
2876    @ATMT.receive_condition(SENT_AP_REQ, prio=1)
2877    def receive_krb_error_as_req(self, pkt):
2878        # We check for a PREAUTH_REQUIRED error. This means that preauth is required
2879        # and we need to do a second exchange.
2880        if Kerberos in pkt and isinstance(pkt.root, KRB_ERROR):
2881            if pkt.root.errorCode == 25:  # KDC_ERR_PREAUTH_REQUIRED
2882                if not self.key and (not self.upn or not self.password):
2883                    log_runtime.error(
2884                        "Got 'KDC_ERR_PREAUTH_REQUIRED', "
2885                        "but no key, nor upn+pass was passed."
2886                    )
2887                    raise self.FINAL()
2888                self._process_padatas_and_key(pkt.root.eData.seq)
2889                self.should_followup = True
2890                self.pre_auth = True
2891                raise self.BEGIN()
2892            else:
2893                log_runtime.error("Received KRB_ERROR")
2894                pkt.show()
2895                raise self.FINAL()
2896
2897    @ATMT.receive_condition(SENT_AP_REQ, prio=2)
2898    def receive_as_rep(self, pkt):
2899        if Kerberos in pkt and isinstance(pkt.root, KRB_AS_REP):
2900            raise self.FINAL().action_parameters(pkt)
2901
2902    @ATMT.eof(SENT_AP_REQ)
2903    def retry_after_eof_in_apreq(self):
2904        if self.should_followup:
2905            # Reconnect and Restart
2906            self.should_followup = False
2907            self.update_sock(self._connect())
2908            raise self.BEGIN()
2909        else:
2910            log_runtime.error("Socket was closed in an unexpected state")
2911            raise self.FINAL()
2912
2913    @ATMT.action(receive_as_rep)
2914    def decrypt_as_rep(self, pkt):
2915        self._process_padatas_and_key(pkt.root.padata)
2916        if not self.pre_auth:
2917            log_runtime.warning("Pre-authentication was disabled for this account !")
2918        # Decrypt
2919        enc = pkt.root.encPart
2920        res = enc.decrypt(self.key)
2921        self.result = self.RES_AS_MODE(pkt.root, res.key.toKey(), res)
2922
2923    @ATMT.receive_condition(SENT_TGS_REQ)
2924    def receive_krb_error_tgs_req(self, pkt):
2925        if Kerberos in pkt and isinstance(pkt.root, KRB_ERROR):
2926            log_runtime.warning("Received KRB_ERROR")
2927            pkt.show()
2928            raise self.FINAL()
2929
2930    @ATMT.receive_condition(SENT_TGS_REQ)
2931    def receive_tgs_rep(self, pkt):
2932        if Kerberos in pkt and isinstance(pkt.root, KRB_TGS_REP):
2933            if not self.renew and pkt.root.ticket.sname.nameString[0].val == b"krbtgt":
2934                log_runtime.warning("Received a cross-realm referral ticket !")
2935            raise self.FINAL().action_parameters(pkt)
2936
2937    @ATMT.action(receive_tgs_rep)
2938    def decrypt_tgs_rep(self, pkt):
2939        # Decrypt
2940        enc = pkt.root.encPart
2941        res = enc.decrypt(self.key)
2942        self.result = self.RES_TGS_MODE(pkt.root, res.key.toKey(), res)
2943
2944    @ATMT.state(final=1)
2945    def FINAL(self):
2946        pass
2947
2948
2949def _parse_upn(upn):
2950    m = re.match(r"^([^@\\/]+)(@|\\|/)([^@\\/]+)$", upn)
2951    if not m:
2952        raise ValueError("Invalid UPN: '%s'" % upn)
2953    if m.group(2) == "@":
2954        user = m.group(1)
2955        domain = m.group(3)
2956    else:
2957        user = m.group(3)
2958        domain = m.group(1)
2959    return user, domain
2960
2961
2962def _parse_spn(spn):
2963    m = re.match(r"^((?:[^@\\/]+)/(?:[^@\\/]+))(?:@([^@\\/]+))?$", spn)
2964    if not m:
2965        raise ValueError("Invalid SPN: '%s'" % spn)
2966    return m.group(1), m.group(2)
2967
2968
2969def krb_as_req(
2970    upn, spn=None, ip=None, key=None, password=None, realm=None, host="WIN10", **kwargs
2971):
2972    r"""
2973    Kerberos AS-Req
2974
2975    :param upn: the user principal name formatted as "DOMAIN\user", "DOMAIN/user"
2976                or "user@DOMAIN"
2977    :param spn: (optional) the full service principal name.
2978                Defaults to "krbtgt/<realm>"
2979    :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for
2980               _kerberos._tcp.dc._msdcs.domain.local).
2981    :param key: (optional) pass the Key object.
2982    :param password: (optional) otherwise, pass the user's password
2983    :param realm: (optional) the realm to use. Otherwise use the one from UPN.
2984    :param host: (optional) the host performing the AS-Req. WIN10 by default.
2985
2986    :return: returns a named tuple (asrep=<...>, sessionkey=<...>)
2987
2988    Example::
2989
2990        >>> # The KDC is on 192.168.122.17, we ask a TGT for user1
2991        >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", password="Password1")
2992
2993    Equivalent::
2994
2995        >>> from scapy.libs.rfc3961 import Key, EncryptionType
2996        >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546
2997        ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9"))
2998        >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", key=key)
2999    """
3000    if realm is None:
3001        _, realm = _parse_upn(upn)
3002    if key is None:
3003        if password is None:
3004            try:
3005                from prompt_toolkit import prompt
3006
3007                password = prompt("Enter password: ", is_password=True)
3008            except ImportError:
3009                password = input("Enter password: ")
3010    cli = KerberosClient(
3011        mode=KerberosClient.MODE.AS_REQ,
3012        realm=realm,
3013        ip=ip,
3014        spn=spn or "krbtgt/" + realm,
3015        host=host,
3016        upn=upn,
3017        password=password,
3018        key=key,
3019        **kwargs,
3020    )
3021    cli.run()
3022    cli.stop()
3023    return cli.result
3024
3025
3026def krb_tgs_req(
3027    upn,
3028    spn,
3029    sessionkey,
3030    ticket,
3031    ip=None,
3032    renew=False,
3033    realm=None,
3034    additional_tickets=[],
3035    u2u=False,
3036    etypes=None,
3037    for_user=None,
3038    s4u2proxy=False,
3039    **kwargs,
3040):
3041    r"""
3042    Kerberos TGS-Req
3043
3044    :param upn: the user principal name formatted as "DOMAIN\user", "DOMAIN/user"
3045                or "user@DOMAIN"
3046    :param spn: the full service principal name (e.g. "cifs/srv1")
3047    :param sessionkey: the session key retrieved from the tgt
3048    :param ticket: the tgt ticket
3049    :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for
3050               _kerberos._tcp.dc._msdcs.domain.local).
3051    :param renew: ask for renewal
3052    :param realm: (optional) the realm to use. Otherwise use the one from SPN.
3053    :param additional_tickets: (optional) a list of additional tickets to pass.
3054    :param u2u: (optional) if specified, enable U2U and request the ticket to be
3055                signed using the session key from the first additional ticket.
3056    :param etypes: array of EncryptionType values.
3057                   By default: AES128, AES256, RC4, DES_MD5
3058    :param for_user: a user principal name to request the ticket for. This is the
3059                     S4U2Self extension.
3060
3061    :return: returns a named tuple (tgsrep=<...>, sessionkey=<...>)
3062
3063    Example::
3064
3065        >>> # The KDC is on 192.168.122.17, we ask a TGT for user1
3066        >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", password="Password1")
3067
3068    Equivalent::
3069
3070        >>> from scapy.libs.rfc3961 import Key, EncryptionType
3071        >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546
3072        ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9"))
3073        >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", key=key)
3074    """
3075    cli = KerberosClient(
3076        mode=KerberosClient.MODE.TGS_REQ,
3077        realm=realm,
3078        upn=upn,
3079        ip=ip,
3080        spn=spn,
3081        key=sessionkey,
3082        ticket=ticket,
3083        renew=renew,
3084        additional_tickets=additional_tickets,
3085        u2u=u2u,
3086        etypes=etypes,
3087        for_user=for_user,
3088        s4u2proxy=s4u2proxy,
3089        **kwargs,
3090    )
3091    cli.run()
3092    cli.stop()
3093    return cli.result
3094
3095
3096def krb_as_and_tgs(upn, spn, ip=None, key=None, password=None, **kwargs):
3097    """
3098    Kerberos AS-Req then TGS-Req
3099    """
3100    res = krb_as_req(upn=upn, ip=ip, key=key, password=password, **kwargs)
3101    if not res:
3102        return
3103    return krb_tgs_req(
3104        upn=upn,
3105        spn=spn,
3106        sessionkey=res.sessionkey,
3107        ticket=res.asrep.ticket,
3108        ip=ip,
3109        **kwargs,
3110    )
3111
3112
3113def krb_get_salt(upn, ip=None, realm=None, host="WIN10", **kwargs):
3114    """
3115    Kerberos AS-Req only to get the salt associated with the UPN.
3116    """
3117    if realm is None:
3118        _, realm = _parse_upn(upn)
3119    cli = KerberosClient(
3120        mode=KerberosClient.MODE.GET_SALT,
3121        realm=realm,
3122        ip=ip,
3123        spn="krbtgt/" + realm,
3124        upn=upn,
3125        host=host,
3126        **kwargs,
3127    )
3128    cli.run()
3129    cli.stop()
3130    return cli.result
3131
3132
3133def kpasswd(
3134    upn,
3135    targetupn=None,
3136    ip=None,
3137    password=None,
3138    newpassword=None,
3139    key=None,
3140    ticket=None,
3141    realm=None,
3142    ssp=None,
3143    setpassword=None,
3144    timeout=3,
3145    port=464,
3146    debug=0,
3147    **kwargs,
3148):
3149    """
3150    Change a password using RFC3244's Kerberos Set / Change Password.
3151
3152    :param upn: the UPN to use for authentication
3153    :param targetupn: (optional) the UPN to change the password of. If not specified,
3154                      same as upn.
3155    :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for
3156               _kerberos._tcp.dc._msdcs.domain.local).
3157    :param key: (optional) pass the Key object.
3158    :param ticket: (optional) a ticket to use. Either a TGT or ST for kadmin/changepw.
3159    :param password: (optional) otherwise, pass the user's password
3160    :param realm: (optional) the realm to use. Otherwise use the one from UPN.
3161    :param setpassword: (optional) use "Set Password" mechanism.
3162    :param ssp: (optional) a Kerberos SSP for the service kadmin/changepw@REALM.
3163                If provided, you probably don't need anything else. Otherwise built.
3164    """
3165    from scapy.layers.ldap import dclocator
3166
3167    if not realm:
3168        _, realm = _parse_upn(upn)
3169    spn = "kadmin/changepw@%s" % realm
3170    if ip is None:
3171        ip = dclocator(
3172            realm,
3173            timeout=timeout,
3174            # Use connect mode instead of ldap for compatibility
3175            # with MIT kerberos servers
3176            mode="connect",
3177            port=port,
3178            debug=debug,
3179        ).ip
3180    if ssp is None and ticket is not None:
3181        tktspn = ticket.getSPN().split("/")[0]
3182        assert tktspn in ["krbtgt", "kadmin"], "Unexpected ticket type ! %s" % tktspn
3183        if tktspn == "krbtgt":
3184            log_runtime.info(
3185                "Using 'Set Password' mode. This only works with admin privileges."
3186            )
3187            setpassword = True
3188            resp = krb_tgs_req(
3189                upn=upn,
3190                spn=spn,
3191                ticket=ticket,
3192                sessionkey=key,
3193                ip=ip,
3194                debug=debug,
3195            )
3196            if resp is None:
3197                return
3198            ticket = resp.tgsrep.ticket
3199            key = resp.sessionkey
3200    if setpassword is None:
3201        setpassword = bool(targetupn)
3202    elif setpassword and targetupn is None:
3203        targetupn = upn
3204    assert setpassword or not targetupn, "Cannot use targetupn in changepassword mode !"
3205    # Get a ticket for kadmin/changepw
3206    if ssp is None:
3207        if ticket is None:
3208            # Get a ticket for kadmin/changepw through AS-REQ
3209            resp = krb_as_req(
3210                upn=upn,
3211                spn=spn,
3212                key=key,
3213                ip=ip,
3214                password=password,
3215                debug=debug,
3216            )
3217            if resp is None:
3218                return
3219            ticket = resp.asrep.ticket
3220            key = resp.sessionkey
3221        ssp = KerberosSSP(
3222            UPN=upn,
3223            SPN=spn,
3224            ST=ticket,
3225            KEY=key,
3226            DC_IP=ip,
3227            debug=debug,
3228            **kwargs,
3229        )
3230    Context, tok, negResult = ssp.GSS_Init_sec_context(
3231        None,
3232        req_flags=0,  # No GSS_C_MUTUAL_FLAG
3233    )
3234    if negResult != GSS_S_CONTINUE_NEEDED:
3235        warning("SSP failed on initial GSS_Init_sec_context !")
3236        if tok:
3237            tok.show()
3238        return
3239    apreq = tok.innerToken.root
3240    # Connect
3241    sock = socket.socket()
3242    sock.settimeout(timeout)
3243    sock.connect((ip, port))
3244    sock = StreamSocket(sock, KpasswdTCPHeader)
3245    # Do KPASSWD request
3246    if newpassword is None:
3247        try:
3248            from prompt_toolkit import prompt
3249
3250            newpassword = prompt("Enter NEW password: ", is_password=True)
3251        except ImportError:
3252            newpassword = input("Enter NEW password: ")
3253    krbpriv = KRB_PRIV(encPart=EncryptedData())
3254    krbpriv.encPart.encrypt(
3255        Context.KrbSessionKey,
3256        EncKrbPrivPart(
3257            sAddress=HostAddress(
3258                addrType=ASN1_INTEGER(2),  # IPv4
3259                address=ASN1_STRING(b"\xc0\xa8\x00e"),
3260            ),
3261            userData=ASN1_STRING(
3262                bytes(
3263                    ChangePasswdData(
3264                        newpasswd=newpassword,
3265                        targname=PrincipalName.fromUPN(targetupn),
3266                        targrealm=realm,
3267                    )
3268                )
3269                if setpassword
3270                else newpassword
3271            ),
3272            timestamp=None,
3273            usec=None,
3274            seqNumber=Context.SendSeqNum,
3275        ),
3276    )
3277    resp = sock.sr1(
3278        KpasswdTCPHeader()
3279        / KPASSWD_REQ(
3280            pvno=0xFF80 if setpassword else 1,
3281            apreq=apreq,
3282            krbpriv=krbpriv,
3283        ),
3284        timeout=timeout,
3285        verbose=0,
3286    )
3287    # Verify KPASSWD response
3288    if not resp:
3289        raise TimeoutError("KPASSWD_REQ timed out !")
3290    if KPASSWD_REP not in resp:
3291        resp.show()
3292        raise ValueError("Invalid response to KPASSWD_REQ !")
3293    Context, tok, negResult = ssp.GSS_Init_sec_context(Context, resp.aprep)
3294    if negResult != GSS_S_COMPLETE:
3295        warning("SSP failed on subsequent GSS_Init_sec_context !")
3296        if tok:
3297            tok.show()
3298        return
3299    # Parse answer KRB_PRIV
3300    krbanswer = resp.krbpriv.encPart.decrypt(Context.KrbSessionKey)
3301    userRep = KPasswdRepData(krbanswer.userData.val)
3302    if userRep.resultCode != 0:
3303        warning(userRep.sprintf("KPASSWD failed !"))
3304        userRep.show()
3305        return
3306    print(userRep.sprintf("%resultCode%"))
3307
3308
3309# SSP
3310
3311
3312class KerberosSSP(SSP):
3313    """
3314    The KerberosSSP
3315
3316    Client settings:
3317
3318    :param ST: the service ticket to use for access.
3319               If not provided, will be retrieved
3320    :param SPN: the SPN of the service to use
3321    :param UPN: The client UPN
3322    :param DC_IP: (optional) is ST+KEY are not provided, will need to contact
3323                  the KDC at this IP. If not provided, will perform dc locator.
3324    :param TGT: (optional) pass a TGT to use to get the ST.
3325    :param KEY: the session key associated with the ST if it is provided,
3326                OR the session key associated with the TGT
3327                OR the kerberos key associated with the UPN
3328    :param PASSWORD: (optional) if a UPN is provided and not a KEY, this is the
3329                     password of the UPN.
3330    :param U2U: (optional) use U2U when requesting the ST.
3331
3332    Server settings:
3333
3334    :param SPN: the SPN of the service to use
3335    :param KEY: the kerberos key to use to decrypt the AP-req
3336    :param TGT: (optional) pass a TGT to use for U2U
3337    :param DC_IP: (optional) if TGT is not provided, request one on the KDC at
3338                  this IP using using the KEY when using U2U.
3339    :param REQUIRE_U2U: (optional, default False) require U2U
3340    """
3341
3342    oid = "1.2.840.113554.1.2.2"
3343    auth_type = 0x10
3344
3345    class STATE(SSP.STATE):
3346        INIT = 1
3347        CLI_SENT_TGTREQ = 2
3348        CLI_SENT_APREQ = 3
3349        CLI_RCVD_APREP = 4
3350        SRV_SENT_APREP = 5
3351
3352    class CONTEXT(SSP.CONTEXT):
3353        __slots__ = [
3354            "SessionKey",
3355            "ServerHostname",
3356            "U2U",
3357            "KrbSessionKey",  # raw Key object
3358            "STSessionKey",  # raw ST Key object (for DCE_STYLE)
3359            "SeqNum",  # for AP
3360            "SendSeqNum",  # for MIC
3361            "RecvSeqNum",  # for MIC
3362            "IsAcceptor",
3363            "SendSealKeyUsage",
3364            "SendSignKeyUsage",
3365            "RecvSealKeyUsage",
3366            "RecvSignKeyUsage",
3367        ]
3368
3369        def __init__(self, IsAcceptor, req_flags=None):
3370            self.state = KerberosSSP.STATE.INIT
3371            self.SessionKey = None
3372            self.ServerHostname = None
3373            self.U2U = False
3374            self.SendSeqNum = 0
3375            self.RecvSeqNum = 0
3376            self.KrbSessionKey = None
3377            self.STSessionKey = None
3378            self.IsAcceptor = IsAcceptor
3379            # [RFC 4121] sect 2
3380            if IsAcceptor:
3381                self.SendSealKeyUsage = 22
3382                self.SendSignKeyUsage = 23
3383                self.RecvSealKeyUsage = 24
3384                self.RecvSignKeyUsage = 25
3385            else:
3386                self.SendSealKeyUsage = 24
3387                self.SendSignKeyUsage = 25
3388                self.RecvSealKeyUsage = 22
3389                self.RecvSignKeyUsage = 23
3390            super(KerberosSSP.CONTEXT, self).__init__(req_flags=req_flags)
3391
3392        def clifailure(self):
3393            self.__init__(self.IsAcceptor, req_flags=self.flags)
3394
3395        def __repr__(self):
3396            if self.U2U:
3397                return "KerberosSSP-U2U"
3398            return "KerberosSSP"
3399
3400    def __init__(
3401        self,
3402        ST=None,
3403        UPN=None,
3404        PASSWORD=None,
3405        U2U=False,
3406        KEY=None,
3407        SPN=None,
3408        TGT=None,
3409        DC_IP=None,
3410        REQUIRE_U2U=False,
3411        SKEY_TYPE=None,
3412        debug=0,
3413        **kwargs,
3414    ):
3415        self.ST = ST
3416        self.UPN = UPN
3417        self.KEY = KEY
3418        self.SPN = SPN
3419        self.TGT = TGT
3420        self.PASSWORD = PASSWORD
3421        self.U2U = U2U
3422        self.DC_IP = DC_IP
3423        self.REQUIRE_U2U = REQUIRE_U2U
3424        self.debug = debug
3425        if SKEY_TYPE is None:
3426            from scapy.libs.rfc3961 import EncryptionType
3427
3428            SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96
3429        self.SKEY_TYPE = SKEY_TYPE
3430        super(KerberosSSP, self).__init__(**kwargs)
3431
3432    def GSS_GetMICEx(self, Context, msgs, qop_req=0):
3433        """
3434        [MS-KILE] sect 3.4.5.6
3435
3436        - AES: RFC4121 sect 4.2.6.1
3437        """
3438        if Context.KrbSessionKey.etype in [17, 18]:  # AES
3439            # Concatenate the ToSign
3440            ToSign = b"".join(x.data for x in msgs if x.sign)
3441            sig = KRB_InnerToken(
3442                TOK_ID=b"\x04\x04",
3443                root=KRB_GSS_MIC(
3444                    Flags="AcceptorSubkey"
3445                    + ("+SentByAcceptor" if Context.IsAcceptor else ""),
3446                    SND_SEQ=Context.SendSeqNum,
3447                ),
3448            )
3449            ToSign += bytes(sig)[:16]
3450            sig.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum(
3451                keyusage=Context.SendSignKeyUsage,
3452                text=ToSign,
3453            )
3454        else:
3455            raise NotImplementedError
3456        Context.SendSeqNum += 1
3457        return sig
3458
3459    def GSS_VerifyMICEx(self, Context, msgs, signature):
3460        """
3461        [MS-KILE] sect 3.4.5.7
3462
3463        - AES: RFC4121 sect 4.2.6.1
3464        """
3465        Context.RecvSeqNum = signature.root.SND_SEQ
3466        if Context.KrbSessionKey.etype in [17, 18]:  # AES
3467            # Concatenate the ToSign
3468            ToSign = b"".join(x.data for x in msgs if x.sign)
3469            ToSign += bytes(signature)[:16]
3470            sig = Context.KrbSessionKey.make_checksum(
3471                keyusage=Context.RecvSignKeyUsage,
3472                text=ToSign,
3473            )
3474        else:
3475            raise NotImplementedError
3476        if sig != signature.root.SGN_CKSUM:
3477            raise ValueError("ERROR: Checksums don't match")
3478
3479    def GSS_WrapEx(self, Context, msgs, qop_req=0):
3480        """
3481        [MS-KILE] sect 3.4.5.4
3482
3483        - AES: RFC4121 sect 4.2.6.2 and [MS-KILE] sect 3.4.5.4.1
3484        - HMAC-RC4: RFC4757 sect 7.3 and [MS-KILE] sect 3.4.5.4.1
3485        """
3486        # Is confidentiality in use?
3487        confidentiality = (Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG) and any(
3488            x.conf_req_flag for x in msgs
3489        )
3490        if Context.KrbSessionKey.etype in [17, 18]:  # AES
3491            # Build token
3492            tok = KRB_InnerToken(
3493                TOK_ID=b"\x05\x04",
3494                root=KRB_GSS_Wrap(
3495                    Flags="AcceptorSubkey"
3496                    + ("+SentByAcceptor" if Context.IsAcceptor else "")
3497                    + ("+Sealed" if confidentiality else ""),
3498                    SND_SEQ=Context.SendSeqNum,
3499                    RRC=0,
3500                ),
3501            )
3502            Context.SendSeqNum += 1
3503            # Real separation starts now: RFC4121 sect 4.2.4
3504            if confidentiality:
3505                # Confidentiality is requested (see RFC4121 sect 4.3)
3506                # {"header" | encrypt(plaintext-data | filler | "header")}
3507                # 0. Roll confounder
3508                Confounder = os.urandom(Context.KrbSessionKey.ep.blocksize)
3509                # 1. Concatenate the data to be encrypted
3510                Data = b"".join(x.data for x in msgs if x.conf_req_flag)
3511                DataLen = len(Data)
3512                # 2. Add filler
3513                tok.root.EC = ((-DataLen) % Context.KrbSessionKey.ep.blocksize) or 16
3514                Filler = b"\x00" * tok.root.EC
3515                Data += Filler
3516                # 3. Add first 16 octets of the Wrap token "header"
3517                PlainHeader = bytes(tok)[:16]
3518                Data += PlainHeader
3519                # 4. Build 'ToSign', exclusively used for checksum
3520                ToSign = Confounder
3521                ToSign += b"".join(x.data for x in msgs if x.sign)
3522                ToSign += Filler
3523                ToSign += PlainHeader
3524                # 5. Finalize token for signing
3525                # "The RRC field is [...] 28 if encryption is requested."
3526                tok.root.RRC = 28
3527                # 6. encrypt() is the encryption operation (which provides for
3528                # integrity protection)
3529                Data = Context.KrbSessionKey.encrypt(
3530                    keyusage=Context.SendSealKeyUsage,
3531                    plaintext=Data,
3532                    confounder=Confounder,
3533                    signtext=ToSign,
3534                )
3535                # 7. Rotate
3536                Data = strrot(Data, tok.root.RRC + tok.root.EC)
3537                # 8. Split (token and encrypted messages)
3538                toklen = len(Data) - DataLen
3539                tok.root.Data = Data[:toklen]
3540                offset = toklen
3541                for msg in msgs:
3542                    msglen = len(msg.data)
3543                    if msg.conf_req_flag:
3544                        msg.data = Data[offset : offset + msglen]
3545                        offset += msglen
3546                return msgs, tok
3547            else:
3548                # No confidentiality is requested
3549                # {"header" | plaintext-data | get_mic(plaintext-data | "header")}
3550                # 0. Concatenate the data
3551                Data = b"".join(x.data for x in msgs if x.sign)
3552                DataLen = len(Data)
3553                # 1. Add first 16 octets of the Wrap token "header"
3554                ToSign = Data
3555                ToSign += bytes(tok)[:16]
3556                # 2. get_mic() is the checksum operation for the required
3557                # checksum mechanism
3558                Mic = Context.KrbSessionKey.make_checksum(
3559                    keyusage=Context.SendSealKeyUsage,
3560                    text=ToSign,
3561                )
3562                # In Wrap tokens without confidentiality, the EC field SHALL be used
3563                # to encode the number of octets in the trailing checksum
3564                tok.root.EC = 12  # len(tok.root.Data) == 12 for AES
3565                # "The RRC field ([RFC4121] section 4.2.5) is 12 if no encryption
3566                # is requested"
3567                tok.root.RRC = 12
3568                # 3. Concat and pack
3569                for msg in msgs:
3570                    if msg.sign:
3571                        msg.data = b""
3572                Data = Data + Mic
3573                # 4. Rotate
3574                tok.root.Data = strrot(Data, tok.root.RRC)
3575                return msgs, tok
3576        elif Context.KrbSessionKey.etype in [23, 24]:  # RC4
3577            from scapy.libs.rfc3961 import (
3578                Cipher,
3579                Hmac_MD5,
3580                _rfc1964pad,
3581                decrepit_algorithms,
3582            )
3583
3584            # Build token
3585            seq = struct.pack(">I", Context.SendSeqNum)
3586            tok = KRB_InnerToken(
3587                TOK_ID=b"\x02\x01",
3588                root=KRB_GSS_Wrap_RFC1964(
3589                    SGN_ALG="HMAC",
3590                    SEAL_ALG="RC4" if confidentiality else "none",
3591                    SND_SEQ=seq
3592                    + (
3593                        # See errata
3594                        b"\xff\xff\xff\xff"
3595                        if Context.IsAcceptor
3596                        else b"\x00\x00\x00\x00"
3597                    ),
3598                ),
3599            )
3600            Context.SendSeqNum += 1
3601            # 0. Concatenate data
3602            ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign))
3603            ToEncrypt = b"".join(x.data for x in msgs if x.conf_req_flag)
3604            Kss = Context.KrbSessionKey.key
3605            # 1. Roll confounder
3606            Confounder = os.urandom(8)
3607            # 2. Compute the 'Kseq' key
3608            Klocal = strxor(Kss, len(Kss) * b"\xf0")
3609            if Context.KrbSessionKey.etype == 24:  # EXP
3610                Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00")
3611                Kcrypt = Kcrypt[:7] + b"\xab" * 9
3612            else:
3613                Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00")
3614            Kcrypt = Hmac_MD5(Kcrypt).digest(seq)
3615            # 3. Build SGN_CKSUM
3616            tok.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum(
3617                keyusage=13,  # See errata
3618                text=bytes(tok)[:8] + Confounder + ToSign,
3619            )[:8]
3620            # 4. Populate token + encrypt
3621            if confidentiality:
3622                # 'encrypt' is requested
3623                rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor()
3624                tok.root.CONFOUNDER = rc4.update(Confounder)
3625                Data = rc4.update(ToEncrypt)
3626                # Split encrypted data
3627                offset = 0
3628                for msg in msgs:
3629                    msglen = len(msg.data)
3630                    if msg.conf_req_flag:
3631                        msg.data = Data[offset : offset + msglen]
3632                        offset += msglen
3633            else:
3634                # 'encrypt' is not requested
3635                tok.root.CONFOUNDER = Confounder
3636            # 5. Compute the 'Kseq' key
3637            if Context.KrbSessionKey.etype == 24:  # EXP
3638                Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00")
3639                Kseq = Kseq[:7] + b"\xab" * 9
3640            else:
3641                Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00")
3642            Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM)
3643            # 6. Encrypt 'SND_SEQ'
3644            rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor()
3645            tok.root.SND_SEQ = rc4.update(tok.root.SND_SEQ)
3646            # 7. Include 'InitialContextToken pseudo ASN.1 header'
3647            tok = KRB_GSSAPI_Token(
3648                MechType="1.2.840.113554.1.2.2",  # Kerberos 5
3649                innerToken=tok,
3650            )
3651            return msgs, tok
3652        else:
3653            raise NotImplementedError
3654
3655    def GSS_UnwrapEx(self, Context, msgs, signature):
3656        """
3657        [MS-KILE] sect 3.4.5.5
3658
3659        - AES: RFC4121 sect 4.2.6.2
3660        - HMAC-RC4: RFC4757 sect 7.3
3661        """
3662        if Context.KrbSessionKey.etype in [17, 18]:  # AES
3663            confidentiality = signature.root.Flags.Sealed
3664            # Real separation starts now: RFC4121 sect 4.2.4
3665            if confidentiality:
3666                # 0. Concatenate the data
3667                Data = signature.root.Data
3668                Data += b"".join(x.data for x in msgs if x.conf_req_flag)
3669                # 1. Un-Rotate
3670                Data = strrot(Data, signature.root.RRC + signature.root.EC, right=False)
3671
3672                # 2. Function to build 'ToSign', exclusively used for checksum
3673                def MakeToSign(Confounder, DecText):
3674                    offset = 0
3675                    # 2.a Confounder
3676                    ToSign = Confounder
3677                    # 2.b Messages
3678                    for msg in msgs:
3679                        msglen = len(msg.data)
3680                        if msg.conf_req_flag:
3681                            ToSign += DecText[offset : offset + msglen]
3682                            offset += msglen
3683                        elif msg.sign:
3684                            ToSign += msg.data
3685                    # 2.c Filler & Padding
3686                    ToSign += DecText[offset:]
3687                    return ToSign
3688
3689                # 3. Decrypt
3690                Data = Context.KrbSessionKey.decrypt(
3691                    keyusage=Context.RecvSealKeyUsage,
3692                    ciphertext=Data,
3693                    presignfunc=MakeToSign,
3694                )
3695                # 4. Split
3696                Data, f16header = (
3697                    Data[:-16],
3698                    Data[-16:],
3699                )
3700                # 5. Check header
3701                hdr = signature.copy()
3702                hdr.root.RRC = 0
3703                if f16header != bytes(hdr)[:16]:
3704                    raise ValueError("ERROR: Headers don't match")
3705                # 6. Split (and ignore filler)
3706                offset = 0
3707                for msg in msgs:
3708                    msglen = len(msg.data)
3709                    if msg.conf_req_flag:
3710                        msg.data = Data[offset : offset + msglen]
3711                        offset += msglen
3712                # Case without msgs
3713                if len(msgs) == 1 and not msgs[0].data:
3714                    msgs[0].data = Data
3715                return msgs
3716            else:
3717                # No confidentiality is requested
3718                # 0. Concatenate the data
3719                Data = signature.root.Data
3720                Data += b"".join(x.data for x in msgs if x.sign)
3721                # 1. Un-Rotate
3722                Data = strrot(Data, signature.root.RRC, right=False)
3723                # 2. Split
3724                Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :]
3725                # "Both the EC field and the RRC field in
3726                # the token header SHALL be filled with zeroes for the purpose of
3727                # calculating the checksum."
3728                ToSign = Data
3729                hdr = signature.copy()
3730                hdr.root.RRC = 0
3731                hdr.root.EC = 0
3732                # Concatenate the data
3733                ToSign += bytes(hdr)[:16]
3734                # 3. Calculate the signature
3735                sig = Context.KrbSessionKey.make_checksum(
3736                    keyusage=Context.RecvSealKeyUsage,
3737                    text=ToSign,
3738                )
3739                # 4. Compare
3740                if sig != Mic:
3741                    raise ValueError("ERROR: Checksums don't match")
3742                # Case without msgs
3743                if len(msgs) == 1 and not msgs[0].data:
3744                    msgs[0].data = Data
3745                return msgs
3746        elif Context.KrbSessionKey.etype in [23, 24]:  # RC4
3747            from scapy.libs.rfc3961 import (
3748                Cipher,
3749                Hmac_MD5,
3750                _rfc1964pad,
3751                decrepit_algorithms,
3752            )
3753
3754            # Drop wrapping
3755            tok = signature.innerToken
3756
3757            # Detect confidentiality
3758            confidentiality = tok.root.SEAL_ALG != 0xFFFF
3759
3760            # 0. Concatenate data
3761            ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag)
3762            Kss = Context.KrbSessionKey.key
3763            # 1. Compute the 'Kseq' key
3764            if Context.KrbSessionKey.etype == 24:  # EXP
3765                Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00")
3766                Kseq = Kseq[:7] + b"\xab" * 9
3767            else:
3768                Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00")
3769            Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM)
3770            # 2. Decrypt 'SND_SEQ'
3771            rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor()
3772            seq = rc4.update(tok.root.SND_SEQ)[:4]
3773            # 3. Compute the 'Kcrypt' key
3774            Klocal = strxor(Kss, len(Kss) * b"\xf0")
3775            if Context.KrbSessionKey.etype == 24:  # EXP
3776                Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00")
3777                Kcrypt = Kcrypt[:7] + b"\xab" * 9
3778            else:
3779                Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00")
3780            Kcrypt = Hmac_MD5(Kcrypt).digest(seq)
3781            # 4. Decrypt
3782            if confidentiality:
3783                # 'encrypt' was requested
3784                rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor()
3785                Confounder = rc4.update(tok.root.CONFOUNDER)
3786                Data = rc4.update(ToDecrypt)
3787                # Split encrypted data
3788                offset = 0
3789                for msg in msgs:
3790                    msglen = len(msg.data)
3791                    if msg.conf_req_flag:
3792                        msg.data = Data[offset : offset + msglen]
3793                        offset += msglen
3794            else:
3795                # 'encrypt' was not requested
3796                Confounder = tok.root.CONFOUNDER
3797            # 5. Verify SGN_CKSUM
3798            ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign))
3799            Context.KrbSessionKey.verify_checksum(
3800                keyusage=13,  # See errata
3801                text=bytes(tok)[:8] + Confounder + ToSign,
3802                cksum=tok.root.SGN_CKSUM,
3803            )
3804            return msgs
3805        else:
3806            raise NotImplementedError
3807
3808    def GSS_Init_sec_context(
3809        self, Context: CONTEXT, val=None, req_flags: Optional[GSS_C_FLAGS] = None
3810    ):
3811        if Context is None:
3812            # New context
3813            Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags)
3814
3815        from scapy.libs.rfc3961 import Key
3816
3817        if Context.state == self.STATE.INIT and self.U2U:
3818            # U2U - Get TGT
3819            Context.state = self.STATE.CLI_SENT_TGTREQ
3820            return (
3821                Context,
3822                KRB_GSSAPI_Token(
3823                    MechType="1.2.840.113554.1.2.2.3",  # U2U
3824                    innerToken=KRB_InnerToken(
3825                        TOK_ID=b"\x04\x00",
3826                        root=KRB_TGT_REQ(),
3827                    ),
3828                ),
3829                GSS_S_CONTINUE_NEEDED,
3830            )
3831
3832        if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]:
3833            if not self.UPN:
3834                raise ValueError("Missing UPN attribute")
3835            # Do we have a ST?
3836            if self.ST is None:
3837                # Client sends an AP-req
3838                if not self.SPN:
3839                    raise ValueError("Missing SPN attribute")
3840                additional_tickets = []
3841                if self.U2U:
3842                    try:
3843                        # GSSAPI / Kerberos
3844                        tgt_rep = val.root.innerToken.root
3845                    except AttributeError:
3846                        try:
3847                            # Kerberos
3848                            tgt_rep = val.innerToken.root
3849                        except AttributeError:
3850                            return Context, None, GSS_S_DEFECTIVE_TOKEN
3851                    if not isinstance(tgt_rep, KRB_TGT_REP):
3852                        tgt_rep.show()
3853                        raise ValueError("KerberosSSP: Unexpected token !")
3854                    additional_tickets = [tgt_rep.ticket]
3855                if self.TGT is not None:
3856                    if not self.KEY:
3857                        raise ValueError("Cannot use TGT without the KEY")
3858                    # Use TGT
3859                    res = krb_tgs_req(
3860                        upn=self.UPN,
3861                        spn=self.SPN,
3862                        ip=self.DC_IP,
3863                        sessionkey=self.KEY,
3864                        ticket=self.TGT,
3865                        additional_tickets=additional_tickets,
3866                        u2u=self.U2U,
3867                        debug=self.debug,
3868                    )
3869                else:
3870                    # Ask for TGT then ST
3871                    res = krb_as_and_tgs(
3872                        upn=self.UPN,
3873                        spn=self.SPN,
3874                        ip=self.DC_IP,
3875                        key=self.KEY,
3876                        password=self.PASSWORD,
3877                        additional_tickets=additional_tickets,
3878                        u2u=self.U2U,
3879                        debug=self.debug,
3880                    )
3881                if not res:
3882                    # Failed to retrieve the ticket
3883                    return Context, None, GSS_S_FAILURE
3884                self.ST, self.KEY = res.tgsrep.ticket, res.sessionkey
3885            elif not self.KEY:
3886                raise ValueError("Must provide KEY with ST")
3887            Context.STSessionKey = self.KEY
3888            # Save ServerHostname
3889            if len(self.ST.sname.nameString) == 2:
3890                Context.ServerHostname = self.ST.sname.nameString[1].val.decode()
3891            # Build the KRB-AP
3892            apOptions = ASN1_BIT_STRING("000")
3893            if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG:
3894                apOptions.set(2, "1")  # mutual-required
3895            if self.U2U:
3896                apOptions.set(1, "1")  # use-session-key
3897                Context.U2U = True
3898            ap_req = KRB_AP_REQ(
3899                apOptions=apOptions,
3900                ticket=self.ST,
3901                authenticator=EncryptedData(),
3902            )
3903            # Build the authenticator
3904            now_time = datetime.now(timezone.utc).replace(microsecond=0)
3905            Context.KrbSessionKey = Key.random_to_key(
3906                self.SKEY_TYPE,
3907                os.urandom(16),
3908            )
3909            Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix()
3910            _, crealm = _parse_upn(self.UPN)
3911            ap_req.authenticator.encrypt(
3912                Context.STSessionKey,
3913                KRB_Authenticator(
3914                    crealm=crealm,
3915                    cname=PrincipalName.fromUPN(self.UPN),
3916                    # RFC 4121 checksum
3917                    cksum=Checksum(
3918                        cksumtype="KRB-AUTHENTICATOR",
3919                        checksum=KRB_AuthenticatorChecksum(Flags=int(Context.flags)),
3920                    ),
3921                    ctime=ASN1_GENERALIZED_TIME(now_time),
3922                    cusec=ASN1_INTEGER(0),
3923                    subkey=EncryptionKey.fromKey(Context.KrbSessionKey),
3924                    seqNumber=Context.SendSeqNum,
3925                    encAuthorizationData=AuthorizationData(
3926                        seq=[
3927                            AuthorizationDataItem(
3928                                adType="AD-IF-RELEVANT",
3929                                adData=AuthorizationData(
3930                                    seq=[
3931                                        AuthorizationDataItem(
3932                                            adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS",
3933                                            adData=KERB_AD_RESTRICTION_ENTRY(
3934                                                restriction=LSAP_TOKEN_INFO_INTEGRITY(
3935                                                    MachineID=bytes(RandBin(32))
3936                                                )
3937                                            ),
3938                                        ),
3939                                        AuthorizationDataItem(
3940                                            adType="KERB-LOCAL",
3941                                            adData=b"\x00" * 16,
3942                                        ),
3943                                    ]
3944                                ),
3945                            )
3946                        ]
3947                    ),
3948                ),
3949            )
3950            Context.state = self.STATE.CLI_SENT_APREQ
3951            if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE:
3952                # Raw kerberos DCE-STYLE
3953                return Context, ap_req, GSS_S_CONTINUE_NEEDED
3954            else:
3955                # Kerberos wrapper
3956                return (
3957                    Context,
3958                    KRB_GSSAPI_Token(
3959                        innerToken=KRB_InnerToken(
3960                            root=ap_req,
3961                        )
3962                    ),
3963                    GSS_S_CONTINUE_NEEDED,
3964                )
3965
3966        elif Context.state == self.STATE.CLI_SENT_APREQ:
3967            if isinstance(val, KRB_AP_REP):
3968                # Raw AP_REP was passed
3969                ap_rep = val
3970            else:
3971                try:
3972                    # GSSAPI / Kerberos
3973                    ap_rep = val.root.innerToken.root
3974                except AttributeError:
3975                    try:
3976                        # Kerberos
3977                        ap_rep = val.innerToken.root
3978                    except AttributeError:
3979                        try:
3980                            # Raw kerberos DCE-STYLE
3981                            ap_rep = val.root
3982                        except AttributeError:
3983                            return Context, None, GSS_S_DEFECTIVE_TOKEN
3984            if not isinstance(ap_rep, KRB_AP_REP):
3985                return Context, None, GSS_S_DEFECTIVE_TOKEN
3986            # Retrieve SessionKey
3987            repPart = ap_rep.encPart.decrypt(Context.STSessionKey)
3988            if repPart.subkey is not None:
3989                Context.SessionKey = repPart.subkey.keyvalue.val
3990                Context.KrbSessionKey = repPart.subkey.toKey()
3991            # OK !
3992            Context.state = self.STATE.CLI_RCVD_APREP
3993            if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE:
3994                # [MS-KILE] sect 3.4.5.1
3995                # The client MUST generate an additional AP exchange reply message
3996                # exactly as the server would as the final message to send to the
3997                # server.
3998                now_time = datetime.now(timezone.utc).replace(microsecond=0)
3999                cli_ap_rep = KRB_AP_REP(encPart=EncryptedData())
4000                cli_ap_rep.encPart.encrypt(
4001                    Context.STSessionKey,
4002                    EncAPRepPart(
4003                        ctime=ASN1_GENERALIZED_TIME(now_time),
4004                        seqNumber=repPart.seqNumber,
4005                        subkey=None,
4006                    ),
4007                )
4008                return Context, cli_ap_rep, GSS_S_COMPLETE
4009            return Context, None, GSS_S_COMPLETE
4010        elif (
4011            Context.state == self.STATE.CLI_RCVD_APREP
4012            and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE
4013        ):
4014            # DCE_STYLE with SPNEGOSSP
4015            return Context, None, GSS_S_COMPLETE
4016        else:
4017            raise ValueError("KerberosSSP: Unknown state")
4018
4019    def _setup_u2u(self):
4020        if not self.TGT:
4021            # Get a TGT for ourselves
4022            try:
4023                upn = "@".join(self.SPN.split("/")[1].split(".", 1))
4024            except KeyError:
4025                raise ValueError("Couldn't transform the SPN into a valid UPN")
4026            res = krb_as_req(upn, self.DC_IP, key=self.KEY)
4027            self.TGT, self.KEY = res.asrep.ticket, res.sessionkey
4028
4029    def GSS_Accept_sec_context(self, Context: CONTEXT, val=None):
4030        if Context is None:
4031            # New context
4032            Context = self.CONTEXT(IsAcceptor=True, req_flags=0)
4033
4034        from scapy.libs.rfc3961 import Key
4035
4036        if Context.state == self.STATE.INIT:
4037            if not self.SPN:
4038                raise ValueError("Missing SPN attribute")
4039            # Server receives AP-req, sends AP-rep
4040            if isinstance(val, KRB_AP_REQ):
4041                # Raw AP_REQ was passed
4042                ap_req = val
4043            else:
4044                try:
4045                    # GSSAPI/Kerberos
4046                    ap_req = val.root.innerToken.root
4047                except AttributeError:
4048                    try:
4049                        # Raw Kerberos
4050                        ap_req = val.root
4051                    except AttributeError:
4052                        return Context, None, GSS_S_DEFECTIVE_TOKEN
4053            if isinstance(ap_req, KRB_TGT_REQ):
4054                # Special U2U case
4055                self._setup_u2u()
4056                Context.U2U = True
4057                return (
4058                    None,
4059                    KRB_GSSAPI_Token(
4060                        MechType="1.2.840.113554.1.2.2.3",  # U2U
4061                        innerToken=KRB_InnerToken(
4062                            TOK_ID=b"\x04\x01",
4063                            root=KRB_TGT_REP(
4064                                ticket=self.TGT,
4065                            ),
4066                        ),
4067                    ),
4068                    GSS_S_CONTINUE_NEEDED,
4069                )
4070            elif not isinstance(ap_req, KRB_AP_REQ):
4071                ap_req.show()
4072                raise ValueError("Unexpected type in KerberosSSP")
4073            if not self.KEY:
4074                raise ValueError("Missing KEY attribute")
4075            # Validate SPN
4076            tkt_spn = "/".join(
4077                x.val.decode() for x in ap_req.ticket.sname.nameString[:2]
4078            ).lower()
4079            if tkt_spn not in [self.SPN.lower(), self.SPN.lower().split(".", 1)[0]]:
4080                warning("KerberosSSP: bad SPN: %s != %s" % (tkt_spn, self.SPN))
4081                return Context, None, GSS_S_BAD_MECH
4082            # Enforce U2U if required
4083            if self.REQUIRE_U2U and ap_req.apOptions.val[1] != "1":  # use-session-key
4084                # Required but not provided. Return an error
4085                self._setup_u2u()
4086                Context.U2U = True
4087                now_time = datetime.now(timezone.utc).replace(microsecond=0)
4088                err = KRB_GSSAPI_Token(
4089                    innerToken=KRB_InnerToken(
4090                        TOK_ID=b"\x03\x00",
4091                        root=KRB_ERROR(
4092                            errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED",
4093                            stime=ASN1_GENERALIZED_TIME(now_time),
4094                            realm=ap_req.ticket.realm,
4095                            sname=ap_req.ticket.sname,
4096                            eData=KRB_TGT_REP(
4097                                ticket=self.TGT,
4098                            ),
4099                        ),
4100                    )
4101                )
4102                return Context, err, GSS_S_CONTINUE_NEEDED
4103            # Decrypt the ticket
4104            try:
4105                tkt = ap_req.ticket.encPart.decrypt(self.KEY)
4106            except ValueError as ex:
4107                warning("KerberosSSP: %s (bad KEY?)" % ex)
4108                now_time = datetime.now(timezone.utc).replace(microsecond=0)
4109                err = KRB_GSSAPI_Token(
4110                    innerToken=KRB_InnerToken(
4111                        TOK_ID=b"\x03\x00",
4112                        root=KRB_ERROR(
4113                            errorCode="KRB_AP_ERR_MODIFIED",
4114                            stime=ASN1_GENERALIZED_TIME(now_time),
4115                            realm=ap_req.ticket.realm,
4116                            sname=ap_req.ticket.sname,
4117                            eData=None,
4118                        ),
4119                    )
4120                )
4121                return Context, err, GSS_S_DEFECTIVE_TOKEN
4122            # Get AP-REP session key
4123            Context.STSessionKey = tkt.key.toKey()
4124            authenticator = ap_req.authenticator.decrypt(Context.STSessionKey)
4125            # Compute an application session key ([MS-KILE] sect 3.1.1.2)
4126            subkey = None
4127            if ap_req.apOptions.val[2] == "1":  # mutual-required
4128                appkey = Key.random_to_key(
4129                    self.SKEY_TYPE,
4130                    os.urandom(16),
4131                )
4132                Context.KrbSessionKey = appkey
4133                Context.SessionKey = appkey.key
4134                subkey = EncryptionKey.fromKey(appkey)
4135            else:
4136                Context.KrbSessionKey = self.KEY
4137                Context.SessionKey = self.KEY.key
4138            # Eventually process the "checksum"
4139            if authenticator.cksum:
4140                if authenticator.cksum.cksumtype == 0x8003:
4141                    # KRB-Authenticator
4142                    Context.flags = authenticator.cksum.checksum.Flags
4143            # Build response (RFC4120 sect 3.2.4)
4144            ap_rep = KRB_AP_REP(encPart=EncryptedData())
4145            ap_rep.encPart.encrypt(
4146                Context.STSessionKey,
4147                EncAPRepPart(
4148                    ctime=authenticator.ctime,
4149                    cusec=authenticator.cusec,
4150                    seqNumber=None,
4151                    subkey=subkey,
4152                ),
4153            )
4154            Context.state = self.STATE.SRV_SENT_APREP
4155            if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE:
4156                # [MS-KILE] sect 3.4.5.1
4157                return Context, ap_rep, GSS_S_CONTINUE_NEEDED
4158            return Context, ap_rep, GSS_S_COMPLETE  # success
4159        elif (
4160            Context.state == self.STATE.SRV_SENT_APREP
4161            and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE
4162        ):
4163            # [MS-KILE] sect 3.4.5.1
4164            # The server MUST receive the additional AP exchange reply message and
4165            # verify that the message is constructed correctly.
4166            if not val:
4167                return Context, None, GSS_S_DEFECTIVE_TOKEN
4168            # Server receives AP-req, sends AP-rep
4169            if isinstance(val, KRB_AP_REP):
4170                # Raw AP_REP was passed
4171                ap_rep = val
4172            else:
4173                try:
4174                    # GSSAPI/Kerberos
4175                    ap_rep = val.root.innerToken.root
4176                except AttributeError:
4177                    try:
4178                        # Raw Kerberos
4179                        ap_rep = val.root
4180                    except AttributeError:
4181                        return Context, None, GSS_S_DEFECTIVE_TOKEN
4182            # Decrypt the AP-REP
4183            try:
4184                ap_rep.encPart.decrypt(Context.STSessionKey)
4185            except ValueError as ex:
4186                warning("KerberosSSP: %s (bad KEY?)" % ex)
4187                return Context, None, GSS_S_DEFECTIVE_TOKEN
4188            return Context, None, GSS_S_COMPLETE  # success
4189        else:
4190            raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state))
4191
4192    def GSS_Passive(self, Context: CONTEXT, val=None):
4193        if Context is None:
4194            Context = self.CONTEXT(True)
4195            Context.passive = True
4196
4197        if Context.state == self.STATE.INIT:
4198            Context, _, status = self.GSS_Accept_sec_context(Context, val)
4199            Context.state = self.STATE.CLI_SENT_APREQ
4200            return Context, GSS_S_CONTINUE_NEEDED
4201        elif Context.state == self.STATE.CLI_SENT_APREQ:
4202            Context, _, status = self.GSS_Init_sec_context(Context, val)
4203            return Context, status
4204
4205    def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False):
4206        if Context.IsAcceptor is not IsAcceptor:
4207            return
4208        # Swap everything
4209        Context.SendSealKeyUsage, Context.RecvSealKeyUsage = (
4210            Context.RecvSealKeyUsage,
4211            Context.SendSealKeyUsage,
4212        )
4213        Context.SendSignKeyUsage, Context.RecvSignKeyUsage = (
4214            Context.RecvSignKeyUsage,
4215            Context.SendSignKeyUsage,
4216        )
4217        Context.IsAcceptor = not Context.IsAcceptor
4218
4219    def MaximumSignatureLength(self, Context: CONTEXT):
4220        if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG:
4221            # TODO: support DES
4222            if Context.KrbSessionKey.etype in [17, 18]:  # AES
4223                return 76
4224            elif Context.KrbSessionKey.etype in [23, 24]:  # RC4_HMAC
4225                return 45
4226            else:
4227                raise NotImplementedError
4228        else:
4229            return 28
4230
4231    def canMechListMIC(self, Context: CONTEXT):
4232        return bool(Context.KrbSessionKey)
4233