Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/layers/kerberos.py: 38%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1647 statements  

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- PKINIT and its extensions: RFC4556, RFC8070, RFC8636 and [MS-PKCA] 

17- User to User Kerberos Authentication: draft-ietf-cat-user2user-03 

18- Public Key Cryptography Based User-to-User Authentication (PKU2U): draft-zhu-pku2u-09 

19- Initial and Pass Through Authentication Using Kerberos V5 (IAKERB): 

20 draft-ietf-kitten-iakerb-03 

21- Kerberos Protocol Extensions: [MS-KILE] 

22- Kerberos Protocol Extensions: Service for User: [MS-SFU] 

23- Kerberos Key Distribution Center Proxy Protocol: [MS-KKDCP] 

24 

25 

26.. note:: 

27 You will find more complete documentation for this layer over at 

28 `Kerberos <https://scapy.readthedocs.io/en/latest/layers/kerberos.html>`_ 

29 

30Example decryption:: 

31 

32 >>> from scapy.libs.rfc3961 import Key, EncryptionType 

33 >>> pkt = Ether(hex_bytes("525400695813525400216c2b08004500015da71840008006dc\ 

34 83c0a87a9cc0a87a11c209005854f6ab2392c25bd650182014b6e00000000001316a8201\ 

35 2d30820129a103020105a20302010aa3633061304ca103020102a24504433041a0030201\ 

36 12a23a043848484decb01c9b62a1cabfbc3f2d1ed85aa5e093ba8358a8cea34d4393af93\ 

37 bf211e274fa58e814878db9f0d7a28d94e7327660db4f3704b3011a10402020080a20904\ 

38 073005a0030101ffa481b73081b4a00703050040810010a1123010a003020101a1093007\ 

39 1b0577696e3124a20e1b0c444f4d41494e2e4c4f43414ca321301fa003020102a1183016\ 

40 1b066b72627467741b0c444f4d41494e2e4c4f43414ca511180f32303337303931333032\ 

41 343830355aa611180f32303337303931333032343830355aa7060204701cc5d1a8153013\ 

42 0201120201110201170201180202ff79020103a91d301b3019a003020114a11204105749\ 

43 4e31202020202020202020202020")) 

44 >>> enc = pkt[Kerberos].root.padata[0].padataValue 

45 >>> k = Key(enc.etype.val, key=hex_bytes("7fada4e566ae4fb270e2800a23a\ 

46 e87127a819d42e69b5e22de0ddc63da80096d")) 

47 >>> enc.decrypt(k) 

48""" 

49 

50from collections import namedtuple, deque 

51from datetime import datetime, timedelta, timezone 

52from enum import IntEnum 

53 

54import os 

55import re 

56import socket 

57import struct 

58 

59from scapy.error import warning 

60import scapy.asn1.mib # noqa: F401 

61from scapy.asn1.ber import BER_id_dec, BER_Decoding_Error 

62from scapy.asn1.asn1 import ( 

63 ASN1_BIT_STRING, 

64 ASN1_BOOLEAN, 

65 ASN1_Class, 

66 ASN1_GENERAL_STRING, 

67 ASN1_GENERALIZED_TIME, 

68 ASN1_INTEGER, 

69 ASN1_STRING, 

70 ASN1_Codecs, 

71) 

72from scapy.asn1fields import ( 

73 ASN1F_BIT_STRING_ENCAPS, 

74 ASN1F_BOOLEAN, 

75 ASN1F_CHOICE, 

76 ASN1F_enum_INTEGER, 

77 ASN1F_FLAGS, 

78 ASN1F_GENERAL_STRING, 

79 ASN1F_GENERALIZED_TIME, 

80 ASN1F_INTEGER, 

81 ASN1F_OID, 

82 ASN1F_optional, 

83 ASN1F_PACKET, 

84 ASN1F_SEQUENCE_OF, 

85 ASN1F_SEQUENCE, 

86 ASN1F_STRING_ENCAPS, 

87 ASN1F_STRING_PacketField, 

88 ASN1F_STRING, 

89) 

90from scapy.asn1packet import ASN1_Packet 

91from scapy.automaton import Automaton, ATMT 

92from scapy.config import conf 

93from scapy.compat import bytes_encode 

94from scapy.error import log_runtime 

95from scapy.fields import ( 

96 ConditionalField, 

97 FieldLenField, 

98 FlagsField, 

99 IntEnumField, 

100 LEIntEnumField, 

101 LenField, 

102 LEShortEnumField, 

103 LEShortField, 

104 LongField, 

105 MayEnd, 

106 MultipleTypeField, 

107 PacketField, 

108 PacketLenField, 

109 PacketListField, 

110 PadField, 

111 ShortEnumField, 

112 ShortField, 

113 StrField, 

114 StrFieldUtf16, 

115 StrFixedLenEnumField, 

116 XByteField, 

117 XLEIntEnumField, 

118 XLEIntField, 

119 XLEShortField, 

120 XStrField, 

121 XStrFixedLenField, 

122 XStrLenField, 

123) 

124from scapy.packet import Packet, bind_bottom_up, bind_top_down, bind_layers 

125from scapy.supersocket import StreamSocket, SuperSocket 

126from scapy.utils import strrot, strxor 

127from scapy.volatile import GeneralizedTime, RandNum, RandBin 

128 

129from scapy.layers.gssapi import ( 

130 GSSAPI_BLOB, 

131 GSS_C_FLAGS, 

132 GSS_C_NO_CHANNEL_BINDINGS, 

133 GSS_S_BAD_BINDINGS, 

134 GSS_S_BAD_MECH, 

135 GSS_S_COMPLETE, 

136 GSS_S_CONTINUE_NEEDED, 

137 GSS_S_DEFECTIVE_TOKEN, 

138 GSS_S_FAILURE, 

139 GSS_S_FLAGS, 

140 GssChannelBindings, 

141 SSP, 

142 _GSSAPI_OIDS, 

143 _GSSAPI_SIGNATURE_OIDS, 

144) 

145from scapy.layers.inet import TCP, UDP 

146from scapy.layers.smb import _NV_VERSION 

147from scapy.layers.smb2 import STATUS_ERREF 

148from scapy.layers.tls.cert import Cert, PrivKey 

149from scapy.layers.x509 import ( 

150 _CMS_ENCAPSULATED, 

151 CMS_ContentInfo, 

152 CMS_IssuerAndSerialNumber, 

153 DHPublicKey, 

154 X509_AlgorithmIdentifier, 

155 X509_DirectoryName, 

156 X509_SubjectPublicKeyInfo, 

157) 

158 

159# Redirect exports from RFC3961 

160try: 

161 from scapy.libs.rfc3961 import * # noqa: F401,F403 

162except ImportError: 

163 pass 

164 

165# Typing imports 

166from typing import ( 

167 Optional, 

168) 

169 

170 

171# kerberos APPLICATION 

172 

173 

174class ASN1_Class_KRB(ASN1_Class): 

175 name = "Kerberos" 

176 # APPLICATION + CONSTRUCTED = 0x40 | 0x20 

177 Token = 0x60 | 0 # GSSAPI 

178 Ticket = 0x60 | 1 

179 Authenticator = 0x60 | 2 

180 EncTicketPart = 0x60 | 3 

181 AS_REQ = 0x60 | 10 

182 AS_REP = 0x60 | 11 

183 TGS_REQ = 0x60 | 12 

184 TGS_REP = 0x60 | 13 

185 AP_REQ = 0x60 | 14 

186 AP_REP = 0x60 | 15 

187 PRIV = 0x60 | 21 

188 CRED = 0x60 | 22 

189 EncASRepPart = 0x60 | 25 

190 EncTGSRepPart = 0x60 | 26 

191 EncAPRepPart = 0x60 | 27 

192 EncKrbPrivPart = 0x60 | 28 

193 EncKrbCredPart = 0x60 | 29 

194 ERROR = 0x60 | 30 

195 

196 

197# RFC4120 sect 5.2 

198 

199 

200KerberosString = ASN1F_GENERAL_STRING 

201Realm = KerberosString 

202Int32 = ASN1F_INTEGER 

203UInt32 = ASN1F_INTEGER 

204 

205_PRINCIPAL_NAME_TYPES = { 

206 0: "NT-UNKNOWN", 

207 1: "NT-PRINCIPAL", 

208 2: "NT-SRV-INST", 

209 3: "NT-SRV-HST", 

210 4: "NT-SRV-XHST", 

211 5: "NT-UID", 

212 6: "NT-X500-PRINCIPAL", 

213 7: "NT-SMTP-NAME", 

214 10: "NT-ENTERPRISE", 

215} 

216 

217 

218class PrincipalName(ASN1_Packet): 

219 ASN1_codec = ASN1_Codecs.BER 

220 ASN1_root = ASN1F_SEQUENCE( 

221 ASN1F_enum_INTEGER( 

222 "nameType", 

223 0, 

224 _PRINCIPAL_NAME_TYPES, 

225 explicit_tag=0xA0, 

226 ), 

227 ASN1F_SEQUENCE_OF("nameString", [], KerberosString, explicit_tag=0xA1), 

228 ) 

229 

230 def toString(self): 

231 """ 

232 Convert a PrincipalName back into its string representation. 

233 """ 

234 return "/".join(x.val.decode() for x in self.nameString) 

235 

236 @staticmethod 

237 def fromUPN(upn: str): 

238 """ 

239 Create a PrincipalName from a UPN string. 

240 """ 

241 user, _ = _parse_upn(upn) 

242 return PrincipalName( 

243 nameString=[ASN1_GENERAL_STRING(user)], 

244 nameType=ASN1_INTEGER(1), # NT-PRINCIPAL 

245 ) 

246 

247 @staticmethod 

248 def fromSPN(spn: str): 

249 """ 

250 Create a PrincipalName from a SPN string. 

251 """ 

252 spn, _ = _parse_spn(spn) 

253 if spn.startswith("krbtgt"): 

254 return PrincipalName( 

255 nameString=[ASN1_GENERAL_STRING(x) for x in spn.split("/")], 

256 nameType=ASN1_INTEGER(2), # NT-SRV-INST 

257 ) 

258 elif "/" in spn: 

259 return PrincipalName( 

260 nameString=[ASN1_GENERAL_STRING(x) for x in spn.split("/")], 

261 nameType=ASN1_INTEGER(3), # NT-SRV-HST 

262 ) 

263 else: 

264 # In case of U2U 

265 return PrincipalName( 

266 nameString=[ASN1_GENERAL_STRING(spn)], 

267 nameType=ASN1_INTEGER(1), # NT-PRINCIPAL 

268 ) 

269 

270 

271KerberosTime = ASN1F_GENERALIZED_TIME 

272Microseconds = ASN1F_INTEGER 

273 

274 

275# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1 

276 

277_KRB_E_TYPES = { 

278 1: "DES-CBC-CRC", 

279 2: "DES-CBC-MD4", 

280 3: "DES-CBC-MD5", 

281 5: "DES3-CBC-MD5", 

282 7: "DES3-CBC-SHA1", 

283 9: "DSAWITHSHA1-CMSOID", 

284 10: "MD5WITHRSAENCRYPTION-CMSOID", 

285 11: "SHA1WITHRSAENCRYPTION-CMSOID", 

286 12: "RC2CBC-ENVOID", 

287 13: "RSAENCRYPTION-ENVOID", 

288 14: "RSAES-OAEP-ENV-OID", 

289 15: "DES-EDE3-CBC-ENV-OID", 

290 16: "DES3-CBC-SHA1-KD", 

291 17: "AES128-CTS-HMAC-SHA1-96", 

292 18: "AES256-CTS-HMAC-SHA1-96", 

293 19: "AES128-CTS-HMAC-SHA256-128", 

294 20: "AES256-CTS-HMAC-SHA384-192", 

295 23: "RC4-HMAC", 

296 24: "RC4-HMAC-EXP", 

297 25: "CAMELLIA128-CTS-CMAC", 

298 26: "CAMELLIA256-CTS-CMAC", 

299} 

300 

301# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-2 

302 

303_KRB_S_TYPES = { 

304 1: "CRC32", 

305 2: "RSA-MD4", 

306 3: "RSA-MD4-DES", 

307 4: "DES-MAC", 

308 5: "DES-MAC-K", 

309 6: "RSA-MD4-DES-K", 

310 7: "RSA-MD5", 

311 8: "RSA-MD5-DES", 

312 9: "RSA-MD5-DES3", 

313 10: "SHA1", 

314 12: "HMAC-SHA1-DES3-KD", 

315 13: "HMAC-SHA1-DES3", 

316 14: "SHA1", 

317 15: "HMAC-SHA1-96-AES128", 

318 16: "HMAC-SHA1-96-AES256", 

319 17: "CMAC-CAMELLIA128", 

320 18: "CMAC-CAMELLIA256", 

321 19: "HMAC-SHA256-128-AES128", 

322 20: "HMAC-SHA384-192-AES256", 

323 # RFC 4121 

324 0x8003: "KRB-AUTHENTICATOR", 

325 # [MS-KILE] 

326 0xFFFFFF76: "MD5", 

327 -138: "MD5", 

328} 

329 

330 

331class EncryptedData(ASN1_Packet): 

332 ASN1_codec = ASN1_Codecs.BER 

333 ASN1_root = ASN1F_SEQUENCE( 

334 ASN1F_enum_INTEGER("etype", 0x17, _KRB_E_TYPES, explicit_tag=0xA0), 

335 ASN1F_optional(UInt32("kvno", None, explicit_tag=0xA1)), 

336 ASN1F_STRING("cipher", "", explicit_tag=0xA2), 

337 ) 

338 

339 def get_usage(self): 

340 """ 

341 Get current key usage number and encrypted class 

342 """ 

343 # RFC 4120 sect 7.5.1 

344 if self.underlayer: 

345 if isinstance(self.underlayer, PADATA): 

346 patype = self.underlayer.padataType 

347 if patype == 2: 

348 # AS-REQ PA-ENC-TIMESTAMP padata timestamp 

349 return 1, PA_ENC_TS_ENC 

350 elif patype == 138: 

351 # RFC6113 PA-ENC-TS-ENC 

352 return 54, PA_ENC_TS_ENC 

353 elif isinstance(self.underlayer, KRB_Ticket): 

354 # AS-REP Ticket and TGS-REP Ticket 

355 return 2, EncTicketPart 

356 elif isinstance(self.underlayer, KRB_AS_REP): 

357 # AS-REP encrypted part 

358 return 3, EncASRepPart 

359 elif isinstance(self.underlayer, KRB_AP_REQ) and isinstance( 

360 self.underlayer.underlayer, PADATA 

361 ): 

362 # TGS-REQ PA-TGS-REQ Authenticator 

363 return 7, KRB_Authenticator 

364 elif isinstance(self.underlayer, KRB_TGS_REP): 

365 # TGS-REP encrypted part 

366 return 8, EncTGSRepPart 

367 elif isinstance(self.underlayer, KRB_AP_REQ): 

368 # AP-REQ Authenticator 

369 return 11, KRB_Authenticator 

370 elif isinstance(self.underlayer, KRB_AP_REP): 

371 # AP-REP encrypted part 

372 return 12, EncAPRepPart 

373 elif isinstance(self.underlayer, KRB_PRIV): 

374 # KRB-PRIV encrypted part 

375 return 13, EncKrbPrivPart 

376 elif isinstance(self.underlayer, KRB_CRED): 

377 # KRB-CRED encrypted part 

378 return 14, EncKrbCredPart 

379 elif isinstance(self.underlayer, KrbFastArmoredReq): 

380 # KEY_USAGE_FAST_ENC 

381 return 51, KrbFastReq 

382 elif isinstance(self.underlayer, KrbFastArmoredRep): 

383 # KEY_USAGE_FAST_REP 

384 return 52, KrbFastResponse 

385 raise ValueError( 

386 "Could not guess key usage number. Please specify key_usage_number" 

387 ) 

388 

389 def decrypt(self, key, key_usage_number=None, cls=None): 

390 """ 

391 Decrypt and return the data contained in cipher. 

392 

393 :param key: the key to use for decryption 

394 :param key_usage_number: (optional) specify the key usage number. 

395 Guessed otherwise 

396 :param cls: (optional) the class of the decrypted payload 

397 Guessed otherwise (or bytes) 

398 """ 

399 if key_usage_number is None: 

400 key_usage_number, cls = self.get_usage() 

401 d = key.decrypt(key_usage_number, self.cipher.val) 

402 if cls: 

403 try: 

404 return cls(d) 

405 except BER_Decoding_Error: 

406 if cls == EncASRepPart: 

407 # https://datatracker.ietf.org/doc/html/rfc4120#section-5.4.2 

408 # "Compatibility note: Some implementations unconditionally send an 

409 # encrypted EncTGSRepPart (application tag number 26) in this field 

410 # regardless of whether the reply is a AS-REP or a TGS-REP. In the 

411 # interest of compatibility, implementors MAY relax the check on the 

412 # tag number of the decrypted ENC-PART." 

413 try: 

414 res = EncTGSRepPart(d) 

415 # https://github.com/krb5/krb5/blob/48ccd81656381522d1f9ccb8705c13f0266a46ab/src/lib/krb5/asn.1/asn1_k_encode.c#L1128 

416 # This is a bug because as the RFC clearly says above, we're 

417 # perfectly in our right to be strict on this. (MAY) 

418 log_runtime.warning( 

419 "Implementation bug detected. This looks like MIT Kerberos." 

420 ) 

421 return res 

422 except BER_Decoding_Error: 

423 pass 

424 raise 

425 return d 

426 

427 def encrypt(self, key, text, confounder=None, key_usage_number=None): 

428 """ 

429 Encrypt text and set it into cipher. 

430 

431 :param key: the key to use for encryption 

432 :param text: the bytes value to encode 

433 :param confounder: (optional) specify the confounder bytes. Random otherwise 

434 :param key_usage_number: (optional) specify the key usage number. 

435 Guessed otherwise 

436 """ 

437 if key_usage_number is None: 

438 key_usage_number = self.get_usage()[0] 

439 self.etype = key.etype 

440 self.cipher = ASN1_STRING( 

441 key.encrypt(key_usage_number, text, confounder=confounder) 

442 ) 

443 

444 

445class EncryptionKey(ASN1_Packet): 

446 ASN1_codec = ASN1_Codecs.BER 

447 ASN1_root = ASN1F_SEQUENCE( 

448 ASN1F_enum_INTEGER("keytype", 0, _KRB_E_TYPES, explicit_tag=0xA0), 

449 ASN1F_STRING("keyvalue", "", explicit_tag=0xA1), 

450 ) 

451 

452 def toKey(self): 

453 from scapy.libs.rfc3961 import Key 

454 

455 return Key( 

456 etype=self.keytype.val, 

457 key=self.keyvalue.val, 

458 ) 

459 

460 @classmethod 

461 def fromKey(self, key): 

462 return EncryptionKey( 

463 keytype=key.etype, 

464 keyvalue=key.key, 

465 ) 

466 

467 

468class _Checksum_Field(ASN1F_STRING_PacketField): 

469 def m2i(self, pkt, s): 

470 val = super(_Checksum_Field, self).m2i(pkt, s) 

471 if not val[0].val: 

472 return val 

473 if pkt.cksumtype.val == 0x8003: 

474 # Special case per RFC 4121 

475 return KRB_AuthenticatorChecksum(val[0].val, _underlayer=pkt), val[1] 

476 return val 

477 

478 

479class Checksum(ASN1_Packet): 

480 ASN1_codec = ASN1_Codecs.BER 

481 ASN1_root = ASN1F_SEQUENCE( 

482 ASN1F_enum_INTEGER( 

483 "cksumtype", 

484 0, 

485 _KRB_S_TYPES, 

486 explicit_tag=0xA0, 

487 ), 

488 _Checksum_Field("checksum", "", explicit_tag=0xA1), 

489 ) 

490 

491 def get_usage(self): 

492 """ 

493 Get current key usage number 

494 """ 

495 # RFC 4120 sect 7.5.1 

496 if self.underlayer: 

497 if isinstance(self.underlayer, KRB_Authenticator): 

498 # TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum 

499 # (n°10 should never happen as we use RFC4121) 

500 return 6 

501 elif isinstance(self.underlayer, PA_FOR_USER): 

502 # [MS-SFU] sect 2.2.1 

503 return 17 

504 elif isinstance(self.underlayer, PA_S4U_X509_USER): 

505 # [MS-SFU] sect 2.2.2 

506 return 26 

507 elif isinstance(self.underlayer, AD_KDCIssued): 

508 # AD-KDC-ISSUED checksum 

509 return 19 

510 elif isinstance(self.underlayer, KrbFastArmoredReq): 

511 # KEY_USAGE_FAST_REQ_CHKSUM 

512 return 50 

513 elif isinstance(self.underlayer, KrbFastFinished): 

514 # KEY_USAGE_FAST_FINISHED 

515 return 53 

516 raise ValueError( 

517 "Could not guess key usage number. Please specify key_usage_number" 

518 ) 

519 

520 def verify(self, key, text, key_usage_number=None): 

521 """ 

522 Decrypt and return the data contained in cipher. 

523 

524 :param key: the key to use to check the checksum 

525 :param text: the bytes to verify 

526 :param key_usage_number: (optional) specify the key usage number. 

527 Guessed otherwise 

528 """ 

529 if key_usage_number is None: 

530 key_usage_number = self.get_usage() 

531 key.verify_checksum(key_usage_number, text, self.checksum.val) 

532 

533 def make(self, key, text, key_usage_number=None, cksumtype=None): 

534 """ 

535 Encrypt text and set it into cipher. 

536 

537 :param key: the key to use to make the checksum 

538 :param text: the bytes to make a checksum of 

539 :param key_usage_number: (optional) specify the key usage number. 

540 Guessed otherwise 

541 """ 

542 if key_usage_number is None: 

543 key_usage_number = self.get_usage() 

544 self.cksumtype = cksumtype or key.cksumtype 

545 self.checksum = ASN1_STRING( 

546 key.make_checksum( 

547 keyusage=key_usage_number, 

548 text=text, 

549 cksumtype=self.cksumtype, 

550 ) 

551 ) 

552 

553 

554KerberosFlags = ASN1F_FLAGS 

555 

556_ADDR_TYPES = { 

557 # RFC4120 sect 7.5.3 

558 0x02: "IPv4", 

559 0x03: "Directional", 

560 0x05: "ChaosNet", 

561 0x06: "XNS", 

562 0x07: "ISO", 

563 0x0C: "DECNET Phase IV", 

564 0x10: "AppleTalk DDP", 

565 0x14: "NetBios", 

566 0x18: "IPv6", 

567} 

568 

569 

570class HostAddress(ASN1_Packet): 

571 ASN1_codec = ASN1_Codecs.BER 

572 ASN1_root = ASN1F_SEQUENCE( 

573 ASN1F_enum_INTEGER( 

574 "addrType", 

575 0, 

576 _ADDR_TYPES, 

577 explicit_tag=0xA0, 

578 ), 

579 ASN1F_STRING("address", "", explicit_tag=0xA1), 

580 ) 

581 

582 

583HostAddresses = lambda name, **kwargs: ASN1F_SEQUENCE_OF( 

584 name, [], HostAddress, **kwargs 

585) 

586 

587 

588_AUTHORIZATIONDATA_VALUES = { 

589 # Filled below 

590} 

591 

592 

593class _AuthorizationData_value_Field(ASN1F_STRING_PacketField): 

594 def m2i(self, pkt, s): 

595 val = super(_AuthorizationData_value_Field, self).m2i(pkt, s) 

596 if not val[0].val: 

597 return val 

598 if pkt.adType.val in _AUTHORIZATIONDATA_VALUES: 

599 return ( 

600 _AUTHORIZATIONDATA_VALUES[pkt.adType.val](val[0].val, _underlayer=pkt), 

601 val[1], 

602 ) 

603 return val 

604 

605 

606_AD_TYPES = { 

607 # RFC4120 sect 7.5.4 

608 1: "AD-IF-RELEVANT", 

609 2: "AD-INTENDED-FOR-SERVER", 

610 3: "AD-INTENDED-FOR-APPLICATION-CLASS", 

611 4: "AD-KDC-ISSUED", 

612 5: "AD-AND-OR", 

613 6: "AD-MANDATORY-TICKET-EXTENSIONS", 

614 7: "AD-IN-TICKET-EXTENSIONS", 

615 8: "AD-MANDATORY-FOR-KDC", 

616 64: "OSF-DCE", 

617 65: "SESAME", 

618 66: "AD-OSD-DCE-PKI-CERTID", 

619 128: "AD-WIN2K-PAC", 

620 129: "AD-ETYPE-NEGOTIATION", 

621 # [MS-KILE] additions 

622 141: "KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

623 142: "KERB-LOCAL", 

624 143: "AD-AUTH-DATA-AP-OPTIONS", 

625 144: "KERB-AUTH-DATA-CLIENT-TARGET", 

626} 

627 

628 

629class AuthorizationDataItem(ASN1_Packet): 

630 ASN1_codec = ASN1_Codecs.BER 

631 ASN1_root = ASN1F_SEQUENCE( 

632 ASN1F_enum_INTEGER( 

633 "adType", 

634 0, 

635 _AD_TYPES, 

636 explicit_tag=0xA0, 

637 ), 

638 _AuthorizationData_value_Field("adData", "", explicit_tag=0xA1), 

639 ) 

640 

641 

642class AuthorizationData(ASN1_Packet): 

643 ASN1_codec = ASN1_Codecs.BER 

644 ASN1_root = ASN1F_SEQUENCE_OF( 

645 "seq", [AuthorizationDataItem()], AuthorizationDataItem 

646 ) 

647 

648 def getAuthData(self, adType): 

649 return next((x.adData for x in self.seq if x.adType == adType), None) 

650 

651 

652AD_IF_RELEVANT = AuthorizationData 

653_AUTHORIZATIONDATA_VALUES[1] = AD_IF_RELEVANT 

654 

655 

656class AD_KDCIssued(ASN1_Packet): 

657 ASN1_codec = ASN1_Codecs.BER 

658 ASN1_root = ASN1F_SEQUENCE( 

659 ASN1F_PACKET("adChecksum", Checksum(), Checksum, explicit_tag=0xA0), 

660 ASN1F_optional( 

661 Realm("iRealm", "", explicit_tag=0xA1), 

662 ), 

663 ASN1F_optional(ASN1F_PACKET("iSname", None, PrincipalName, explicit_tag=0xA2)), 

664 ASN1F_PACKET("elements", None, AuthorizationData, explicit_tag=0xA3), 

665 ) 

666 

667 

668_AUTHORIZATIONDATA_VALUES[4] = AD_KDCIssued 

669 

670 

671class AD_AND_OR(ASN1_Packet): 

672 ASN1_codec = ASN1_Codecs.BER 

673 ASN1_root = ASN1F_SEQUENCE( 

674 Int32("conditionCount", 0, explicit_tag=0xA0), 

675 ASN1F_PACKET("elements", None, AuthorizationData, explicit_tag=0xA1), 

676 ) 

677 

678 

679_AUTHORIZATIONDATA_VALUES[5] = AD_AND_OR 

680 

681ADMANDATORYFORKDC = AuthorizationData 

682_AUTHORIZATIONDATA_VALUES[8] = ADMANDATORYFORKDC 

683 

684 

685# https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xml 

686_PADATA_TYPES = { 

687 1: "PA-TGS-REQ", 

688 2: "PA-ENC-TIMESTAMP", 

689 3: "PA-PW-SALT", 

690 11: "PA-ETYPE-INFO", 

691 14: "PA-PK-AS-REQ-OLD", 

692 15: "PA-PK-AS-REP-OLD", 

693 16: "PA-PK-AS-REQ", 

694 17: "PA-PK-AS-REP", 

695 19: "PA-ETYPE-INFO2", 

696 20: "PA-SVR-REFERRAL-INFO", 

697 111: "TD-CMS-DIGEST-ALGORITHMS", 

698 128: "PA-PAC-REQUEST", 

699 129: "PA-FOR-USER", 

700 130: "PA-FOR-X509-USER", 

701 131: "PA-FOR-CHECK_DUPS", 

702 132: "PA-AS-CHECKSUM", 

703 133: "PA-FX-COOKIE", 

704 134: "PA-AUTHENTICATION-SET", 

705 135: "PA-AUTH-SET-SELECTED", 

706 136: "PA-FX-FAST", 

707 137: "PA-FX-ERROR", 

708 138: "PA-ENCRYPTED-CHALLENGE", 

709 141: "PA-OTP-CHALLENGE", 

710 142: "PA-OTP-REQUEST", 

711 143: "PA-OTP-CONFIRM", 

712 144: "PA-OTP-PIN-CHANGE", 

713 145: "PA-EPAK-AS-REQ", 

714 146: "PA-EPAK-AS-REP", 

715 147: "PA-PKINIT-KX", 

716 148: "PA-PKU2U-NAME", 

717 149: "PA-REQ-ENC-PA-REP", 

718 150: "PA-AS-FRESHNESS", 

719 151: "PA-SPAKE", 

720 161: "KERB-KEY-LIST-REQ", 

721 162: "KERB-KEY-LIST-REP", 

722 165: "PA-SUPPORTED-ENCTYPES", 

723 166: "PA-EXTENDED-ERROR", 

724 167: "PA-PAC-OPTIONS", 

725 170: "KERB-SUPERSEDED-BY-USER", 

726 171: "KERB-DMSA-KEY-PACKAGE", 

727} 

728 

729_PADATA_CLASSES = { 

730 # Filled elsewhere in this file 

731} 

732 

733 

734# RFC4120 

735 

736 

737class _PADATA_value_Field(ASN1F_STRING_PacketField): 

738 """ 

739 A special field that properly dispatches PA-DATA values according to 

740 padata-type and if the paquet is a request or a response. 

741 """ 

742 

743 def m2i(self, pkt, s): 

744 val = super(_PADATA_value_Field, self).m2i(pkt, s) 

745 if pkt.padataType.val in _PADATA_CLASSES: 

746 cls = _PADATA_CLASSES[pkt.padataType.val] 

747 if isinstance(cls, tuple): 

748 parent = pkt.underlayer or pkt.parent 

749 is_reply = False 

750 if parent is not None: 

751 if isinstance(parent, (KRB_AS_REP, KRB_TGS_REP)): 

752 is_reply = True 

753 else: 

754 parent = parent.underlayer or parent.parent 

755 is_reply = isinstance(parent, KRB_ERROR) 

756 cls = cls[is_reply] 

757 if not val[0].val: 

758 return val 

759 return cls(val[0].val, _underlayer=pkt), val[1] 

760 return val 

761 

762 

763class PADATA(ASN1_Packet): 

764 ASN1_codec = ASN1_Codecs.BER 

765 ASN1_root = ASN1F_SEQUENCE( 

766 ASN1F_enum_INTEGER("padataType", 0, _PADATA_TYPES, explicit_tag=0xA1), 

767 _PADATA_value_Field( 

768 "padataValue", 

769 "", 

770 explicit_tag=0xA2, 

771 ), 

772 ) 

773 

774 

775# RFC 4120 sect 5.2.7.2 

776 

777 

778class PA_ENC_TS_ENC(ASN1_Packet): 

779 ASN1_codec = ASN1_Codecs.BER 

780 ASN1_root = ASN1F_SEQUENCE( 

781 KerberosTime("patimestamp", GeneralizedTime(), explicit_tag=0xA0), 

782 ASN1F_optional(Microseconds("pausec", 0, explicit_tag=0xA1)), 

783 ) 

784 

785 

786_PADATA_CLASSES[2] = EncryptedData # PA-ENC-TIMESTAMP 

787_PADATA_CLASSES[138] = EncryptedData # PA-ENCRYPTED-CHALLENGE 

788 

789 

790# RFC 4120 sect 5.2.7.4 

791 

792 

793class ETYPE_INFO_ENTRY(ASN1_Packet): 

794 ASN1_codec = ASN1_Codecs.BER 

795 ASN1_root = ASN1F_SEQUENCE( 

796 ASN1F_enum_INTEGER("etype", 0x1, _KRB_E_TYPES, explicit_tag=0xA0), 

797 ASN1F_optional( 

798 ASN1F_STRING("salt", "", explicit_tag=0xA1), 

799 ), 

800 ) 

801 

802 

803class ETYPE_INFO(ASN1_Packet): 

804 ASN1_codec = ASN1_Codecs.BER 

805 ASN1_root = ASN1F_SEQUENCE_OF("seq", [ETYPE_INFO_ENTRY()], ETYPE_INFO_ENTRY) 

806 

807 

808_PADATA_CLASSES[11] = ETYPE_INFO 

809 

810# RFC 4120 sect 5.2.7.5 

811 

812 

813class ETYPE_INFO_ENTRY2(ASN1_Packet): 

814 ASN1_codec = ASN1_Codecs.BER 

815 ASN1_root = ASN1F_SEQUENCE( 

816 ASN1F_enum_INTEGER("etype", 0x1, _KRB_E_TYPES, explicit_tag=0xA0), 

817 ASN1F_optional( 

818 KerberosString("salt", "", explicit_tag=0xA1), 

819 ), 

820 ASN1F_optional( 

821 ASN1F_STRING("s2kparams", "", explicit_tag=0xA2), 

822 ), 

823 ) 

824 

825 

826class ETYPE_INFO2(ASN1_Packet): 

827 ASN1_codec = ASN1_Codecs.BER 

828 ASN1_root = ASN1F_SEQUENCE_OF("seq", [ETYPE_INFO_ENTRY2()], ETYPE_INFO_ENTRY2) 

829 

830 

831_PADATA_CLASSES[19] = ETYPE_INFO2 

832 

833 

834# RFC8636 - PKINIT Algorithm Agility 

835 

836 

837class TD_CMS_DIGEST_ALGORITHMS(ASN1_Packet): 

838 ASN1_codec = ASN1_Codecs.BER 

839 ASN1_root = ASN1F_SEQUENCE_OF("seq", [], X509_AlgorithmIdentifier) 

840 

841 

842_PADATA_CLASSES[111] = TD_CMS_DIGEST_ALGORITHMS 

843 

844 

845# PADATA Extended with RFC6113 

846 

847 

848class PA_AUTHENTICATION_SET_ELEM(ASN1_Packet): 

849 ASN1_codec = ASN1_Codecs.BER 

850 ASN1_root = ASN1F_SEQUENCE( 

851 Int32("paType", 0, explicit_tag=0xA0), 

852 ASN1F_optional( 

853 ASN1F_STRING("paHint", "", explicit_tag=0xA1), 

854 ), 

855 ASN1F_optional( 

856 ASN1F_STRING("paValue", "", explicit_tag=0xA2), 

857 ), 

858 ) 

859 

860 

861class PA_AUTHENTICATION_SET(ASN1_Packet): 

862 ASN1_codec = ASN1_Codecs.BER 

863 ASN1_root = ASN1F_SEQUENCE_OF( 

864 "elems", [PA_AUTHENTICATION_SET_ELEM()], PA_AUTHENTICATION_SET_ELEM 

865 ) 

866 

867 

868_PADATA_CLASSES[134] = PA_AUTHENTICATION_SET 

869 

870 

871# [MS-KILE] sect 2.2.3 

872 

873 

874class PA_PAC_REQUEST(ASN1_Packet): 

875 ASN1_codec = ASN1_Codecs.BER 

876 ASN1_root = ASN1F_SEQUENCE( 

877 ASN1F_BOOLEAN("includePac", True, explicit_tag=0xA0), 

878 ) 

879 

880 

881_PADATA_CLASSES[128] = PA_PAC_REQUEST 

882 

883 

884# [MS-KILE] sect 2.2.5 

885 

886 

887class LSAP_TOKEN_INFO_INTEGRITY(Packet): 

888 fields_desc = [ 

889 FlagsField( 

890 "Flags", 

891 0, 

892 -32, 

893 { 

894 0x00000001: "UAC-Restricted", 

895 }, 

896 ), 

897 LEIntEnumField( 

898 "TokenIL", 

899 0x00002000, 

900 { 

901 0x00000000: "Untrusted", 

902 0x00001000: "Low", 

903 0x00002000: "Medium", 

904 0x00003000: "High", 

905 0x00004000: "System", 

906 0x00005000: "Protected process", 

907 }, 

908 ), 

909 MayEnd(XStrFixedLenField("MachineID", b"", length=32)), 

910 # KB 5068222 - still waiting for [MS-KILE] update (oct. 2025) 

911 XStrFixedLenField("PermanentMachineID", b"", length=32), 

912 ] 

913 

914 

915# [MS-KILE] sect 2.2.6 

916 

917 

918class _KerbAdRestrictionEntry_Field(ASN1F_STRING_PacketField): 

919 def m2i(self, pkt, s): 

920 val = super(_KerbAdRestrictionEntry_Field, self).m2i(pkt, s) 

921 if not val[0].val: 

922 return val 

923 if pkt.restrictionType.val == 0x0000: # LSAP_TOKEN_INFO_INTEGRITY 

924 return LSAP_TOKEN_INFO_INTEGRITY(val[0].val, _underlayer=pkt), val[1] 

925 return val 

926 

927 

928class KERB_AD_RESTRICTION_ENTRY(ASN1_Packet): 

929 name = "KERB-AD-RESTRICTION-ENTRY" 

930 ASN1_codec = ASN1_Codecs.BER 

931 ASN1_root = ASN1F_SEQUENCE( 

932 ASN1F_SEQUENCE( 

933 ASN1F_enum_INTEGER( 

934 "restrictionType", 

935 0, 

936 {0: "LSAP_TOKEN_INFO_INTEGRITY"}, 

937 explicit_tag=0xA0, 

938 ), 

939 _KerbAdRestrictionEntry_Field("restriction", b"", explicit_tag=0xA1), 

940 ) 

941 ) 

942 

943 

944_AUTHORIZATIONDATA_VALUES[141] = KERB_AD_RESTRICTION_ENTRY 

945 

946 

947# [MS-KILE] sect 3.2.5.8 

948 

949 

950class KERB_AUTH_DATA_AP_OPTIONS(Packet): 

951 name = "KERB-AUTH-DATA-AP-OPTIONS" 

952 fields_desc = [ 

953 LEIntEnumField( 

954 "apOptions", 

955 0x4000, 

956 { 

957 0x4000: "KERB_AP_OPTIONS_CBT", 

958 0x8000: "KERB_AP_OPTIONS_UNVERIFIED_TARGET_NAME", 

959 }, 

960 ), 

961 ] 

962 

963 

964_AUTHORIZATIONDATA_VALUES[143] = KERB_AUTH_DATA_AP_OPTIONS 

965 

966 

967# This has no doc..? [MS-KILE] only mentions its name. 

968 

969 

970class KERB_AUTH_DATA_CLIENT_TARGET(Packet): 

971 name = "KERB-AD-TARGET-PRINCIPAL" 

972 fields_desc = [ 

973 StrFieldUtf16("spn", ""), 

974 ] 

975 

976 

977_AUTHORIZATIONDATA_VALUES[144] = KERB_AUTH_DATA_CLIENT_TARGET 

978 

979 

980# RFC6806 sect 6 

981 

982 

983class KERB_AD_LOGIN_ALIAS(ASN1_Packet): 

984 ASN1_codec = ASN1_Codecs.BER 

985 ASN1_root = ASN1F_SEQUENCE(ASN1F_SEQUENCE_OF("loginAliases", [], PrincipalName)) 

986 

987 

988_AUTHORIZATIONDATA_VALUES[80] = KERB_AD_LOGIN_ALIAS 

989 

990 

991# [MS-KILE] sect 2.2.8 

992 

993 

994class PA_SUPPORTED_ENCTYPES(Packet): 

995 fields_desc = [ 

996 FlagsField( 

997 "flags", 

998 0, 

999 -32, 

1000 [ 

1001 "DES-CBC-CRC", 

1002 "DES-CBC-MD5", 

1003 "RC4-HMAC", 

1004 "AES128-CTS-HMAC-SHA1-96", 

1005 "AES256-CTS-HMAC-SHA1-96", 

1006 ] 

1007 + ["bit_%d" % i for i in range(11)] 

1008 + [ 

1009 "FAST-supported", 

1010 "Compount-identity-supported", 

1011 "Claims-supported", 

1012 "Resource-SID-compression-disabled", 

1013 ], 

1014 ) 

1015 ] 

1016 

1017 

1018_PADATA_CLASSES[165] = PA_SUPPORTED_ENCTYPES 

1019 

1020# [MS-KILE] sect 2.2.10 

1021 

1022 

1023class PA_PAC_OPTIONS(ASN1_Packet): 

1024 ASN1_codec = ASN1_Codecs.BER 

1025 ASN1_root = ASN1F_SEQUENCE( 

1026 KerberosFlags( 

1027 "options", 

1028 "", 

1029 [ 

1030 "Claims", 

1031 "Branch-Aware", 

1032 "Forward-to-Full-DC", 

1033 "Resource-based-constrained-delegation", # [MS-SFU] 2.2.5 

1034 ], 

1035 explicit_tag=0xA0, 

1036 ) 

1037 ) 

1038 

1039 

1040_PADATA_CLASSES[167] = PA_PAC_OPTIONS 

1041 

1042# [MS-KILE] sect 2.2.11 

1043 

1044 

1045class KERB_KEY_LIST_REQ(ASN1_Packet): 

1046 ASN1_codec = ASN1_Codecs.BER 

1047 ASN1_root = ASN1F_SEQUENCE_OF( 

1048 "keytypes", 

1049 [], 

1050 ASN1F_enum_INTEGER("", 0, _KRB_E_TYPES), 

1051 ) 

1052 

1053 

1054_PADATA_CLASSES[161] = KERB_KEY_LIST_REQ 

1055 

1056# [MS-KILE] sect 2.2.12 

1057 

1058 

1059class KERB_KEY_LIST_REP(ASN1_Packet): 

1060 ASN1_codec = ASN1_Codecs.BER 

1061 ASN1_root = ASN1F_SEQUENCE_OF( 

1062 "keys", 

1063 [], 

1064 ASN1F_PACKET("", None, EncryptionKey), 

1065 ) 

1066 

1067 

1068_PADATA_CLASSES[162] = KERB_KEY_LIST_REP 

1069 

1070# [MS-KILE] sect 2.2.13 

1071 

1072 

1073class KERB_SUPERSEDED_BY_USER(ASN1_Packet): 

1074 ASN1_codec = ASN1_Codecs.BER 

1075 ASN1_root = ASN1F_SEQUENCE( 

1076 ASN1F_PACKET("name", None, PrincipalName, explicit_tag=0xA0), 

1077 Realm("realm", None, explicit_tag=0xA1), 

1078 ) 

1079 

1080 

1081_PADATA_CLASSES[170] = KERB_SUPERSEDED_BY_USER 

1082 

1083 

1084# [MS-KILE] sect 2.2.14 

1085 

1086 

1087class KERB_DMSA_KEY_PACKAGE(ASN1_Packet): 

1088 ASN1_codec = ASN1_Codecs.BER 

1089 ASN1_root = ASN1F_SEQUENCE( 

1090 ASN1F_SEQUENCE_OF( 

1091 "currentKeys", 

1092 [], 

1093 ASN1F_PACKET("", None, EncryptionKey), 

1094 explicit_tag=0xA0, 

1095 ), 

1096 ASN1F_optional( 

1097 ASN1F_SEQUENCE_OF( 

1098 "previousKeys", 

1099 [], 

1100 ASN1F_PACKET("", None, EncryptionKey), 

1101 explicit_tag=0xA1, 

1102 ), 

1103 ), 

1104 KerberosTime("expirationInterval", GeneralizedTime(), explicit_tag=0xA2), 

1105 KerberosTime("fetchInterval", GeneralizedTime(), explicit_tag=0xA4), 

1106 ) 

1107 

1108 

1109_PADATA_CLASSES[171] = KERB_DMSA_KEY_PACKAGE 

1110 

1111 

1112# RFC6113 sect 5.4.1 

1113 

1114 

1115class _KrbFastArmor_value_Field(ASN1F_STRING_PacketField): 

1116 def m2i(self, pkt, s): 

1117 val = super(_KrbFastArmor_value_Field, self).m2i(pkt, s) 

1118 if not val[0].val: 

1119 return val 

1120 if pkt.armorType.val == 1: # FX_FAST_ARMOR_AP_REQUEST 

1121 return KRB_AP_REQ(val[0].val, _underlayer=pkt), val[1] 

1122 return val 

1123 

1124 

1125class KrbFastArmor(ASN1_Packet): 

1126 ASN1_codec = ASN1_Codecs.BER 

1127 ASN1_root = ASN1F_SEQUENCE( 

1128 ASN1F_enum_INTEGER( 

1129 "armorType", 1, {1: "FX_FAST_ARMOR_AP_REQUEST"}, explicit_tag=0xA0 

1130 ), 

1131 _KrbFastArmor_value_Field("armorValue", "", explicit_tag=0xA1), 

1132 ) 

1133 

1134 

1135# RFC6113 sect 5.4.2 

1136 

1137 

1138class KrbFastArmoredReq(ASN1_Packet): 

1139 ASN1_codec = ASN1_Codecs.BER 

1140 ASN1_root = ASN1F_SEQUENCE( 

1141 ASN1F_SEQUENCE( 

1142 ASN1F_optional( 

1143 ASN1F_PACKET("armor", None, KrbFastArmor, explicit_tag=0xA0) 

1144 ), 

1145 ASN1F_PACKET("reqChecksum", Checksum(), Checksum, explicit_tag=0xA1), 

1146 ASN1F_PACKET("encFastReq", None, EncryptedData, explicit_tag=0xA2), 

1147 ) 

1148 ) 

1149 

1150 

1151class PA_FX_FAST_REQUEST(ASN1_Packet): 

1152 ASN1_codec = ASN1_Codecs.BER 

1153 ASN1_root = ASN1F_CHOICE( 

1154 "armoredData", 

1155 ASN1_STRING(""), 

1156 ASN1F_PACKET("req", KrbFastArmoredReq, KrbFastArmoredReq, implicit_tag=0xA0), 

1157 ) 

1158 

1159 

1160# RFC6113 sect 5.4.3 

1161 

1162 

1163class KrbFastArmoredRep(ASN1_Packet): 

1164 ASN1_codec = ASN1_Codecs.BER 

1165 ASN1_root = ASN1F_SEQUENCE( 

1166 ASN1F_SEQUENCE( 

1167 ASN1F_PACKET("encFastRep", None, EncryptedData, explicit_tag=0xA0), 

1168 ) 

1169 ) 

1170 

1171 

1172class PA_FX_FAST_REPLY(ASN1_Packet): 

1173 ASN1_codec = ASN1_Codecs.BER 

1174 ASN1_root = ASN1F_CHOICE( 

1175 "armoredData", 

1176 ASN1_STRING(""), 

1177 ASN1F_PACKET("req", KrbFastArmoredRep, KrbFastArmoredRep, implicit_tag=0xA0), 

1178 ) 

1179 

1180 

1181class KrbFastFinished(ASN1_Packet): 

1182 ASN1_codec = ASN1_Codecs.BER 

1183 ASN1_root = ASN1F_SEQUENCE( 

1184 KerberosTime("timestamp", GeneralizedTime(), explicit_tag=0xA0), 

1185 Microseconds("usec", 0, explicit_tag=0xA1), 

1186 Realm("crealm", "", explicit_tag=0xA2), 

1187 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA3), 

1188 ASN1F_PACKET("ticketChecksum", Checksum(), Checksum, explicit_tag=0xA4), 

1189 ) 

1190 

1191 

1192class KrbFastResponse(ASN1_Packet): 

1193 ASN1_codec = ASN1_Codecs.BER 

1194 ASN1_root = ASN1F_SEQUENCE( 

1195 ASN1F_SEQUENCE_OF("padata", [PADATA()], PADATA, explicit_tag=0xA0), 

1196 ASN1F_optional( 

1197 ASN1F_PACKET("strengthenKey", None, EncryptionKey, explicit_tag=0xA1) 

1198 ), 

1199 ASN1F_optional( 

1200 ASN1F_PACKET( 

1201 "finished", KrbFastFinished(), KrbFastFinished, explicit_tag=0xA2 

1202 ) 

1203 ), 

1204 UInt32("nonce", 0, explicit_tag=0xA3), 

1205 ) 

1206 

1207 

1208_PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY) 

1209 

1210 

1211# RFC 4556 - PKINIT 

1212 

1213 

1214# sect 3.2.1 

1215 

1216 

1217class ExternalPrincipalIdentifier(ASN1_Packet): 

1218 ASN1_codec = ASN1_Codecs.BER 

1219 ASN1_root = ASN1F_SEQUENCE( 

1220 ASN1F_optional( 

1221 ASN1F_STRING_ENCAPS( 

1222 "subjectName", None, X509_DirectoryName, implicit_tag=0x80 

1223 ), 

1224 ), 

1225 ASN1F_optional( 

1226 ASN1F_STRING_ENCAPS( 

1227 "issuerAndSerialNumber", 

1228 None, 

1229 CMS_IssuerAndSerialNumber, 

1230 implicit_tag=0x81, 

1231 ), 

1232 ), 

1233 ASN1F_optional( 

1234 ASN1F_STRING("subjectKeyIdentifier", "", implicit_tag=0x82), 

1235 ), 

1236 ) 

1237 

1238 

1239class PA_PK_AS_REQ(ASN1_Packet): 

1240 ASN1_codec = ASN1_Codecs.BER 

1241 ASN1_root = ASN1F_SEQUENCE( 

1242 ASN1F_STRING_ENCAPS( 

1243 "signedAuthpack", 

1244 CMS_ContentInfo(), 

1245 CMS_ContentInfo, 

1246 implicit_tag=0x80, 

1247 ), 

1248 ASN1F_optional( 

1249 ASN1F_SEQUENCE_OF( 

1250 "trustedCertifiers", 

1251 [ExternalPrincipalIdentifier()], 

1252 ExternalPrincipalIdentifier, 

1253 explicit_tag=0xA1, 

1254 ), 

1255 ), 

1256 ASN1F_optional( 

1257 ASN1F_STRING("kdcPkId", "", implicit_tag=0xA2), 

1258 ), 

1259 ) 

1260 

1261 

1262_PADATA_CLASSES[16] = PA_PK_AS_REQ 

1263 

1264 

1265# [MS-PKCA] sect 2.2.3 

1266 

1267 

1268class PAChecksum2(ASN1_Packet): 

1269 ASN1_codec = ASN1_Codecs.BER 

1270 ASN1_root = ASN1F_SEQUENCE( 

1271 ASN1F_STRING("checksum", "", explicit_tag=0xA0), 

1272 ASN1F_PACKET( 

1273 "algorithmIdentifier", 

1274 X509_AlgorithmIdentifier(), 

1275 X509_AlgorithmIdentifier, 

1276 explicit_tag=0xA1, 

1277 ), 

1278 ) 

1279 

1280 

1281# still RFC 4556 sect 3.2.1 

1282 

1283 

1284class PKAuthenticator(ASN1_Packet): 

1285 ASN1_codec = ASN1_Codecs.BER 

1286 ASN1_root = ASN1F_SEQUENCE( 

1287 Microseconds("cusec", 0, explicit_tag=0xA0), 

1288 KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA1), 

1289 UInt32("nonce", 0, explicit_tag=0xA2), 

1290 ASN1F_optional( 

1291 ASN1F_STRING("paChecksum", "", explicit_tag=0xA3), 

1292 ), 

1293 # RFC8070 extension 

1294 ASN1F_optional( 

1295 ASN1F_STRING("freshnessToken", "", explicit_tag=0xA4), 

1296 ), 

1297 # [MS-PKCA] sect 2.2.3 

1298 ASN1F_optional( 

1299 ASN1F_PACKET("paChecksum2", None, PAChecksum2, explicit_tag=0xA5), 

1300 ), 

1301 ) 

1302 

1303 

1304# RFC8636 sect 6 

1305 

1306 

1307class KDFAlgorithmId(ASN1_Packet): 

1308 ASN1_codec = ASN1_Codecs.BER 

1309 ASN1_root = ASN1F_SEQUENCE( 

1310 ASN1F_OID("kdfId", "", explicit_tag=0xA0), 

1311 ) 

1312 

1313 

1314# still RFC 4556 sect 3.2.1 

1315 

1316 

1317class AuthPack(ASN1_Packet): 

1318 ASN1_codec = ASN1_Codecs.BER 

1319 ASN1_root = ASN1F_SEQUENCE( 

1320 ASN1F_PACKET( 

1321 "pkAuthenticator", 

1322 PKAuthenticator(), 

1323 PKAuthenticator, 

1324 explicit_tag=0xA0, 

1325 ), 

1326 ASN1F_optional( 

1327 ASN1F_PACKET( 

1328 "clientPublicValue", 

1329 X509_SubjectPublicKeyInfo(), 

1330 X509_SubjectPublicKeyInfo, 

1331 explicit_tag=0xA1, 

1332 ), 

1333 ), 

1334 ASN1F_optional( 

1335 ASN1F_SEQUENCE_OF( 

1336 "supportedCMSTypes", 

1337 [], 

1338 X509_AlgorithmIdentifier, 

1339 explicit_tag=0xA2, 

1340 ), 

1341 ), 

1342 ASN1F_optional( 

1343 ASN1F_STRING("clientDCNonce", None, explicit_tag=0xA3), 

1344 ), 

1345 # RFC8636 extension 

1346 ASN1F_optional( 

1347 ASN1F_SEQUENCE_OF("supportedKDFs", None, KDFAlgorithmId, explicit_tag=0xA4), 

1348 ), 

1349 ) 

1350 

1351 

1352_CMS_ENCAPSULATED["1.3.6.1.5.2.3.1"] = AuthPack 

1353 

1354# sect 3.2.3 

1355 

1356 

1357class DHRepInfo(ASN1_Packet): 

1358 ASN1_codec = ASN1_Codecs.BER 

1359 ASN1_root = ASN1F_SEQUENCE( 

1360 ASN1F_STRING_ENCAPS( 

1361 "dhSignedData", 

1362 CMS_ContentInfo(), 

1363 CMS_ContentInfo, 

1364 implicit_tag=0x80, 

1365 ), 

1366 ASN1F_optional( 

1367 ASN1F_STRING("serverDHNonce", "", explicit_tag=0xA1), 

1368 ), 

1369 # RFC8636 extension 

1370 ASN1F_optional( 

1371 ASN1F_PACKET("kdf", None, KDFAlgorithmId, explicit_tag=0xA2), 

1372 ), 

1373 ) 

1374 

1375 

1376class EncKeyPack(ASN1_Packet): 

1377 ASN1_codec = ASN1_Codecs.BER 

1378 ASN1_root = ASN1F_STRING("encKeyPack", "") 

1379 

1380 

1381class PA_PK_AS_REP(ASN1_Packet): 

1382 ASN1_codec = ASN1_Codecs.BER 

1383 ASN1_root = ASN1F_CHOICE( 

1384 "rep", 

1385 ASN1_STRING(""), 

1386 ASN1F_PACKET("dhInfo", DHRepInfo(), DHRepInfo, explicit_tag=0xA0), 

1387 ASN1F_PACKET("encKeyPack", EncKeyPack(), EncKeyPack, explicit_tag=0xA1), 

1388 ) 

1389 

1390 

1391_PADATA_CLASSES[17] = PA_PK_AS_REP 

1392 

1393 

1394class KDCDHKeyInfo(ASN1_Packet): 

1395 ASN1_codec = ASN1_Codecs.BER 

1396 ASN1_root = ASN1F_SEQUENCE( 

1397 ASN1F_BIT_STRING_ENCAPS( 

1398 "subjectPublicKey", DHPublicKey(), DHPublicKey, explicit_tag=0xA0 

1399 ), 

1400 UInt32("nonce", 0, explicit_tag=0xA1), 

1401 ASN1F_optional( 

1402 KerberosTime("dhKeyExpiration", None, explicit_tag=0xA2), 

1403 ), 

1404 ) 

1405 

1406 

1407_CMS_ENCAPSULATED["1.3.6.1.5.2.3.2"] = KDCDHKeyInfo 

1408 

1409# [MS-SFU] 

1410 

1411 

1412# sect 2.2.1 

1413class PA_FOR_USER(ASN1_Packet): 

1414 ASN1_codec = ASN1_Codecs.BER 

1415 ASN1_root = ASN1F_SEQUENCE( 

1416 ASN1F_PACKET("userName", PrincipalName(), PrincipalName, explicit_tag=0xA0), 

1417 Realm("userRealm", "", explicit_tag=0xA1), 

1418 ASN1F_PACKET("cksum", Checksum(), Checksum, explicit_tag=0xA2), 

1419 KerberosString("authPackage", "Kerberos", explicit_tag=0xA3), 

1420 ) 

1421 

1422 

1423_PADATA_CLASSES[129] = PA_FOR_USER 

1424 

1425 

1426# sect 2.2.2 

1427 

1428 

1429class S4UUserID(ASN1_Packet): 

1430 ASN1_codec = ASN1_Codecs.BER 

1431 ASN1_root = ASN1F_SEQUENCE( 

1432 UInt32("nonce", 0, explicit_tag=0xA0), 

1433 ASN1F_optional( 

1434 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA1), 

1435 ), 

1436 Realm("crealm", "", explicit_tag=0xA2), 

1437 ASN1F_optional( 

1438 ASN1F_STRING("subjectCertificate", None, explicit_tag=0xA3), 

1439 ), 

1440 ASN1F_optional( 

1441 ASN1F_FLAGS( 

1442 "options", 

1443 "", 

1444 [ 

1445 "reserved", 

1446 "KDC_CHECK_LOGON_HOUR_RESTRICTIONS", 

1447 "USE_REPLY_KEY_USAGE", 

1448 "NT_AUTH_POLICY_NOT_REQUIRED", 

1449 "UNCONDITIONAL_DELEGATION", 

1450 ], 

1451 explicit_tag=0xA4, 

1452 ) 

1453 ), 

1454 ) 

1455 

1456 

1457class PA_S4U_X509_USER(ASN1_Packet): 

1458 ASN1_codec = ASN1_Codecs.BER 

1459 ASN1_root = ASN1F_SEQUENCE( 

1460 ASN1F_PACKET("userId", S4UUserID(), S4UUserID, explicit_tag=0xA0), 

1461 ASN1F_PACKET("checksum", Checksum(), Checksum, explicit_tag=0xA1), 

1462 ) 

1463 

1464 

1465_PADATA_CLASSES[130] = PA_S4U_X509_USER 

1466 

1467 

1468# Back to RFC4120 

1469 

1470# sect 5.10 

1471KRB_MSG_TYPES = { 

1472 1: "Ticket", 

1473 2: "Authenticator", 

1474 3: "EncTicketPart", 

1475 10: "AS-REQ", 

1476 11: "AS-REP", 

1477 12: "TGS-REQ", 

1478 13: "TGS-REP", 

1479 14: "AP-REQ", 

1480 15: "AP-REP", 

1481 16: "KRB-TGT-REQ", # U2U 

1482 17: "KRB-TGT-REP", # U2U 

1483 20: "KRB-SAFE", 

1484 21: "KRB-PRIV", 

1485 22: "KRB-CRED", 

1486 25: "EncASRepPart", 

1487 26: "EncTGSRepPart", 

1488 27: "EncAPRepPart", 

1489 28: "EncKrbPrivPart", 

1490 29: "EnvKrbCredPart", 

1491 30: "KRB-ERROR", 

1492} 

1493 

1494# sect 5.3 

1495 

1496 

1497class KRB_Ticket(ASN1_Packet): 

1498 ASN1_codec = ASN1_Codecs.BER 

1499 ASN1_root = ASN1F_SEQUENCE( 

1500 ASN1F_SEQUENCE( 

1501 ASN1F_INTEGER("tktVno", 5, explicit_tag=0xA0), 

1502 Realm("realm", "", explicit_tag=0xA1), 

1503 ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xA2), 

1504 ASN1F_PACKET("encPart", EncryptedData(), EncryptedData, explicit_tag=0xA3), 

1505 ), 

1506 implicit_tag=ASN1_Class_KRB.Ticket, 

1507 ) 

1508 

1509 def getSPN(self): 

1510 return "%s@%s" % ( 

1511 self.sname.toString(), 

1512 self.realm.val.decode(), 

1513 ) 

1514 

1515 

1516class TransitedEncoding(ASN1_Packet): 

1517 ASN1_codec = ASN1_Codecs.BER 

1518 ASN1_root = ASN1F_SEQUENCE( 

1519 Int32("trType", 0, explicit_tag=0xA0), 

1520 ASN1F_STRING("contents", "", explicit_tag=0xA1), 

1521 ) 

1522 

1523 

1524_TICKET_FLAGS = [ 

1525 "reserved", 

1526 "forwardable", 

1527 "forwarded", 

1528 "proxiable", 

1529 "proxy", 

1530 "may-postdate", 

1531 "postdated", 

1532 "invalid", 

1533 "renewable", 

1534 "initial", 

1535 "pre-authent", 

1536 "hw-authent", 

1537 "transited-since-policy-checked", 

1538 "ok-as-delegate", 

1539 "unused", 

1540 "canonicalize", # RFC6806 

1541 "anonymous", # RFC6112 + RFC8129 

1542] 

1543 

1544 

1545class EncTicketPart(ASN1_Packet): 

1546 ASN1_codec = ASN1_Codecs.BER 

1547 ASN1_root = ASN1F_SEQUENCE( 

1548 ASN1F_SEQUENCE( 

1549 KerberosFlags( 

1550 "flags", 

1551 "", 

1552 _TICKET_FLAGS, 

1553 explicit_tag=0xA0, 

1554 ), 

1555 ASN1F_PACKET("key", EncryptionKey(), EncryptionKey, explicit_tag=0xA1), 

1556 Realm("crealm", "", explicit_tag=0xA2), 

1557 ASN1F_PACKET("cname", PrincipalName(), PrincipalName, explicit_tag=0xA3), 

1558 ASN1F_PACKET( 

1559 "transited", TransitedEncoding(), TransitedEncoding, explicit_tag=0xA4 

1560 ), 

1561 KerberosTime("authtime", GeneralizedTime(), explicit_tag=0xA5), 

1562 ASN1F_optional( 

1563 KerberosTime("starttime", GeneralizedTime(), explicit_tag=0xA6) 

1564 ), 

1565 KerberosTime("endtime", GeneralizedTime(), explicit_tag=0xA7), 

1566 ASN1F_optional( 

1567 KerberosTime("renewTill", GeneralizedTime(), explicit_tag=0xA8), 

1568 ), 

1569 ASN1F_optional( 

1570 HostAddresses("addresses", explicit_tag=0xA9), 

1571 ), 

1572 ASN1F_optional( 

1573 ASN1F_PACKET( 

1574 "authorizationData", None, AuthorizationData, explicit_tag=0xAA 

1575 ), 

1576 ), 

1577 ), 

1578 implicit_tag=ASN1_Class_KRB.EncTicketPart, 

1579 ) 

1580 

1581 

1582# sect 5.4.1 

1583 

1584 

1585class KRB_KDC_REQ_BODY(ASN1_Packet): 

1586 ASN1_codec = ASN1_Codecs.BER 

1587 ASN1_root = ASN1F_SEQUENCE( 

1588 KerberosFlags( 

1589 "kdcOptions", 

1590 "", 

1591 [ 

1592 "reserved", 

1593 "forwardable", 

1594 "forwarded", 

1595 "proxiable", 

1596 "proxy", 

1597 "allow-postdate", 

1598 "postdated", 

1599 "unused7", 

1600 "renewable", 

1601 "unused9", 

1602 "unused10", 

1603 "opt-hardware-auth", 

1604 "unused12", 

1605 "unused13", 

1606 "cname-in-addl-tkt", # [MS-SFU] sect 2.2.3 

1607 "canonicalize", # RFC6806 

1608 "request-anonymous", # RFC6112 + RFC8129 

1609 ] 

1610 + ["unused%d" % i for i in range(17, 26)] 

1611 + [ 

1612 "disable-transited-check", 

1613 "renewable-ok", 

1614 "enc-tkt-in-skey", 

1615 "unused29", 

1616 "renew", 

1617 "validate", 

1618 ], 

1619 explicit_tag=0xA0, 

1620 ), 

1621 ASN1F_optional(ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA1)), 

1622 Realm("realm", "", explicit_tag=0xA2), 

1623 ASN1F_optional( 

1624 ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA3), 

1625 ), 

1626 ASN1F_optional(KerberosTime("from_", None, explicit_tag=0xA4)), 

1627 KerberosTime("till", GeneralizedTime(), explicit_tag=0xA5), 

1628 ASN1F_optional(KerberosTime("rtime", GeneralizedTime(), explicit_tag=0xA6)), 

1629 UInt32("nonce", 0, explicit_tag=0xA7), 

1630 ASN1F_SEQUENCE_OF("etype", [], Int32, explicit_tag=0xA8), 

1631 ASN1F_optional( 

1632 HostAddresses("addresses", explicit_tag=0xA9), 

1633 ), 

1634 ASN1F_optional( 

1635 ASN1F_PACKET( 

1636 "encAuthorizationData", None, EncryptedData, explicit_tag=0xAA 

1637 ), 

1638 ), 

1639 ASN1F_optional( 

1640 ASN1F_SEQUENCE_OF("additionalTickets", [], KRB_Ticket, explicit_tag=0xAB) 

1641 ), 

1642 ) 

1643 

1644 

1645KRB_KDC_REQ = ASN1F_SEQUENCE( 

1646 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA1), 

1647 ASN1F_enum_INTEGER("msgType", 10, KRB_MSG_TYPES, explicit_tag=0xA2), 

1648 ASN1F_optional(ASN1F_SEQUENCE_OF("padata", [], PADATA, explicit_tag=0xA3)), 

1649 ASN1F_PACKET("reqBody", KRB_KDC_REQ_BODY(), KRB_KDC_REQ_BODY, explicit_tag=0xA4), 

1650) 

1651 

1652 

1653class KrbFastReq(ASN1_Packet): 

1654 # RFC6113 sect 5.4.2 

1655 ASN1_codec = ASN1_Codecs.BER 

1656 ASN1_root = ASN1F_SEQUENCE( 

1657 KerberosFlags( 

1658 "fastOptions", 

1659 "", 

1660 [ 

1661 "RESERVED", 

1662 "hide-client-names", 

1663 ] 

1664 + ["res%d" % i for i in range(2, 16)] 

1665 + ["kdc-follow-referrals"], 

1666 explicit_tag=0xA0, 

1667 ), 

1668 ASN1F_SEQUENCE_OF("padata", [PADATA()], PADATA, explicit_tag=0xA1), 

1669 ASN1F_PACKET("reqBody", None, KRB_KDC_REQ_BODY, explicit_tag=0xA2), 

1670 ) 

1671 

1672 

1673class KRB_AS_REQ(ASN1_Packet): 

1674 ASN1_codec = ASN1_Codecs.BER 

1675 ASN1_root = ASN1F_SEQUENCE( 

1676 KRB_KDC_REQ, 

1677 implicit_tag=ASN1_Class_KRB.AS_REQ, 

1678 ) 

1679 

1680 

1681class KRB_TGS_REQ(ASN1_Packet): 

1682 ASN1_codec = ASN1_Codecs.BER 

1683 ASN1_root = ASN1F_SEQUENCE( 

1684 KRB_KDC_REQ, 

1685 implicit_tag=ASN1_Class_KRB.TGS_REQ, 

1686 ) 

1687 msgType = ASN1_INTEGER(12) 

1688 

1689 

1690# sect 5.4.2 

1691 

1692KRB_KDC_REP = ASN1F_SEQUENCE( 

1693 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1694 ASN1F_enum_INTEGER("msgType", 11, KRB_MSG_TYPES, explicit_tag=0xA1), 

1695 ASN1F_optional( 

1696 ASN1F_SEQUENCE_OF("padata", [], PADATA, explicit_tag=0xA2), 

1697 ), 

1698 Realm("crealm", "", explicit_tag=0xA3), 

1699 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA4), 

1700 ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA5), 

1701 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA6), 

1702) 

1703 

1704 

1705class KRB_AS_REP(ASN1_Packet): 

1706 ASN1_codec = ASN1_Codecs.BER 

1707 ASN1_root = ASN1F_SEQUENCE( 

1708 KRB_KDC_REP, 

1709 implicit_tag=ASN1_Class_KRB.AS_REP, 

1710 ) 

1711 

1712 

1713class KRB_TGS_REP(ASN1_Packet): 

1714 ASN1_codec = ASN1_Codecs.BER 

1715 ASN1_root = ASN1F_SEQUENCE( 

1716 KRB_KDC_REP, 

1717 implicit_tag=ASN1_Class_KRB.TGS_REP, 

1718 ) 

1719 

1720 def getUPN(self): 

1721 return "%s@%s" % ( 

1722 self.cname.toString(), 

1723 self.crealm.val.decode(), 

1724 ) 

1725 

1726 

1727class LastReqItem(ASN1_Packet): 

1728 ASN1_codec = ASN1_Codecs.BER 

1729 ASN1_root = ASN1F_SEQUENCE( 

1730 Int32("lrType", 0, explicit_tag=0xA0), 

1731 KerberosTime("lrValue", GeneralizedTime(), explicit_tag=0xA1), 

1732 ) 

1733 

1734 

1735EncKDCRepPart = ASN1F_SEQUENCE( 

1736 ASN1F_PACKET("key", None, EncryptionKey, explicit_tag=0xA0), 

1737 ASN1F_SEQUENCE_OF("lastReq", [], LastReqItem, explicit_tag=0xA1), 

1738 UInt32("nonce", 0, explicit_tag=0xA2), 

1739 ASN1F_optional( 

1740 KerberosTime("keyExpiration", GeneralizedTime(), explicit_tag=0xA3), 

1741 ), 

1742 KerberosFlags( 

1743 "flags", 

1744 "", 

1745 _TICKET_FLAGS, 

1746 explicit_tag=0xA4, 

1747 ), 

1748 KerberosTime("authtime", GeneralizedTime(), explicit_tag=0xA5), 

1749 ASN1F_optional( 

1750 KerberosTime("starttime", GeneralizedTime(), explicit_tag=0xA6), 

1751 ), 

1752 KerberosTime("endtime", GeneralizedTime(), explicit_tag=0xA7), 

1753 ASN1F_optional( 

1754 KerberosTime("renewTill", GeneralizedTime(), explicit_tag=0xA8), 

1755 ), 

1756 Realm("srealm", "", explicit_tag=0xA9), 

1757 ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xAA), 

1758 ASN1F_optional( 

1759 HostAddresses("caddr", explicit_tag=0xAB), 

1760 ), 

1761 # RFC6806 sect 11 

1762 ASN1F_optional( 

1763 ASN1F_SEQUENCE_OF("encryptedPaData", [], PADATA, explicit_tag=0xAC), 

1764 ), 

1765) 

1766 

1767 

1768class EncASRepPart(ASN1_Packet): 

1769 ASN1_codec = ASN1_Codecs.BER 

1770 ASN1_root = ASN1F_SEQUENCE( 

1771 EncKDCRepPart, 

1772 implicit_tag=ASN1_Class_KRB.EncASRepPart, 

1773 ) 

1774 

1775 

1776class EncTGSRepPart(ASN1_Packet): 

1777 ASN1_codec = ASN1_Codecs.BER 

1778 ASN1_root = ASN1F_SEQUENCE( 

1779 EncKDCRepPart, 

1780 implicit_tag=ASN1_Class_KRB.EncTGSRepPart, 

1781 ) 

1782 

1783 

1784# sect 5.5.1 

1785 

1786 

1787class KRB_AP_REQ(ASN1_Packet): 

1788 ASN1_codec = ASN1_Codecs.BER 

1789 ASN1_root = ASN1F_SEQUENCE( 

1790 ASN1F_SEQUENCE( 

1791 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1792 ASN1F_enum_INTEGER("msgType", 14, KRB_MSG_TYPES, explicit_tag=0xA1), 

1793 KerberosFlags( 

1794 "apOptions", 

1795 "", 

1796 [ 

1797 "reserved", 

1798 "use-session-key", 

1799 "mutual-required", 

1800 ], 

1801 explicit_tag=0xA2, 

1802 ), 

1803 ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA3), 

1804 ASN1F_PACKET("authenticator", None, EncryptedData, explicit_tag=0xA4), 

1805 ), 

1806 implicit_tag=ASN1_Class_KRB.AP_REQ, 

1807 ) 

1808 

1809 

1810_PADATA_CLASSES[1] = KRB_AP_REQ 

1811 

1812 

1813class KRB_Authenticator(ASN1_Packet): 

1814 ASN1_codec = ASN1_Codecs.BER 

1815 ASN1_root = ASN1F_SEQUENCE( 

1816 ASN1F_SEQUENCE( 

1817 ASN1F_INTEGER("authenticatorPvno", 5, explicit_tag=0xA0), 

1818 Realm("crealm", "", explicit_tag=0xA1), 

1819 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA2), 

1820 ASN1F_optional( 

1821 ASN1F_PACKET("cksum", None, Checksum, explicit_tag=0xA3), 

1822 ), 

1823 Microseconds("cusec", 0, explicit_tag=0xA4), 

1824 KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA5), 

1825 ASN1F_optional( 

1826 ASN1F_PACKET("subkey", None, EncryptionKey, explicit_tag=0xA6), 

1827 ), 

1828 ASN1F_optional( 

1829 UInt32("seqNumber", 0, explicit_tag=0xA7), 

1830 ), 

1831 ASN1F_optional( 

1832 ASN1F_PACKET( 

1833 "encAuthorizationData", None, AuthorizationData, explicit_tag=0xA8 

1834 ), 

1835 ), 

1836 ), 

1837 implicit_tag=ASN1_Class_KRB.Authenticator, 

1838 ) 

1839 

1840 

1841# sect 5.5.2 

1842 

1843 

1844class KRB_AP_REP(ASN1_Packet): 

1845 ASN1_codec = ASN1_Codecs.BER 

1846 ASN1_root = ASN1F_SEQUENCE( 

1847 ASN1F_SEQUENCE( 

1848 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1849 ASN1F_enum_INTEGER("msgType", 15, KRB_MSG_TYPES, explicit_tag=0xA1), 

1850 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA2), 

1851 ), 

1852 implicit_tag=ASN1_Class_KRB.AP_REP, 

1853 ) 

1854 

1855 

1856class EncAPRepPart(ASN1_Packet): 

1857 ASN1_codec = ASN1_Codecs.BER 

1858 ASN1_root = ASN1F_SEQUENCE( 

1859 ASN1F_SEQUENCE( 

1860 KerberosTime("ctime", GeneralizedTime(), explicit_tag=0xA0), 

1861 Microseconds("cusec", 0, explicit_tag=0xA1), 

1862 ASN1F_optional( 

1863 ASN1F_PACKET("subkey", None, EncryptionKey, explicit_tag=0xA2), 

1864 ), 

1865 ASN1F_optional( 

1866 UInt32("seqNumber", 0, explicit_tag=0xA3), 

1867 ), 

1868 ), 

1869 implicit_tag=ASN1_Class_KRB.EncAPRepPart, 

1870 ) 

1871 

1872 

1873# sect 5.7 

1874 

1875 

1876class KRB_PRIV(ASN1_Packet): 

1877 ASN1_codec = ASN1_Codecs.BER 

1878 ASN1_root = ASN1F_SEQUENCE( 

1879 ASN1F_SEQUENCE( 

1880 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1881 ASN1F_enum_INTEGER("msgType", 21, KRB_MSG_TYPES, explicit_tag=0xA1), 

1882 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA3), 

1883 ), 

1884 implicit_tag=ASN1_Class_KRB.PRIV, 

1885 ) 

1886 

1887 

1888class EncKrbPrivPart(ASN1_Packet): 

1889 ASN1_codec = ASN1_Codecs.BER 

1890 ASN1_root = ASN1F_SEQUENCE( 

1891 ASN1F_SEQUENCE( 

1892 ASN1F_STRING("userData", ASN1_STRING(""), explicit_tag=0xA0), 

1893 ASN1F_optional( 

1894 KerberosTime("timestamp", None, explicit_tag=0xA1), 

1895 ), 

1896 ASN1F_optional( 

1897 Microseconds("usec", None, explicit_tag=0xA2), 

1898 ), 

1899 ASN1F_optional( 

1900 UInt32("seqNumber", None, explicit_tag=0xA3), 

1901 ), 

1902 ASN1F_PACKET("sAddress", None, HostAddress, explicit_tag=0xA4), 

1903 ASN1F_optional( 

1904 ASN1F_PACKET("cAddress", None, HostAddress, explicit_tag=0xA5), 

1905 ), 

1906 ), 

1907 implicit_tag=ASN1_Class_KRB.EncKrbPrivPart, 

1908 ) 

1909 

1910 

1911# sect 5.8 

1912 

1913 

1914class KRB_CRED(ASN1_Packet): 

1915 ASN1_codec = ASN1_Codecs.BER 

1916 ASN1_root = ASN1F_SEQUENCE( 

1917 ASN1F_SEQUENCE( 

1918 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

1919 ASN1F_enum_INTEGER("msgType", 22, KRB_MSG_TYPES, explicit_tag=0xA1), 

1920 ASN1F_SEQUENCE_OF("tickets", [KRB_Ticket()], KRB_Ticket, explicit_tag=0xA2), 

1921 ASN1F_PACKET("encPart", None, EncryptedData, explicit_tag=0xA3), 

1922 ), 

1923 implicit_tag=ASN1_Class_KRB.CRED, 

1924 ) 

1925 

1926 

1927class KrbCredInfo(ASN1_Packet): 

1928 ASN1_codec = ASN1_Codecs.BER 

1929 ASN1_root = ASN1F_SEQUENCE( 

1930 ASN1F_PACKET("key", EncryptionKey(), EncryptionKey, explicit_tag=0xA0), 

1931 ASN1F_optional( 

1932 Realm("prealm", None, explicit_tag=0xA1), 

1933 ), 

1934 ASN1F_optional( 

1935 ASN1F_PACKET("pname", None, PrincipalName, explicit_tag=0xA2), 

1936 ), 

1937 ASN1F_optional( 

1938 KerberosFlags( 

1939 "flags", 

1940 None, 

1941 _TICKET_FLAGS, 

1942 explicit_tag=0xA3, 

1943 ), 

1944 ), 

1945 ASN1F_optional( 

1946 KerberosTime("authtime", None, explicit_tag=0xA4), 

1947 ), 

1948 ASN1F_optional(KerberosTime("starttime", None, explicit_tag=0xA5)), 

1949 ASN1F_optional( 

1950 KerberosTime("endtime", None, explicit_tag=0xA6), 

1951 ), 

1952 ASN1F_optional( 

1953 KerberosTime("renewTill", None, explicit_tag=0xA7), 

1954 ), 

1955 ASN1F_optional( 

1956 Realm("srealm", None, explicit_tag=0xA8), 

1957 ), 

1958 ASN1F_optional( 

1959 ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA9), 

1960 ), 

1961 ASN1F_optional( 

1962 HostAddresses("caddr", explicit_tag=0xAA), 

1963 ), 

1964 ) 

1965 

1966 

1967class EncKrbCredPart(ASN1_Packet): 

1968 ASN1_codec = ASN1_Codecs.BER 

1969 ASN1_root = ASN1F_SEQUENCE( 

1970 ASN1F_SEQUENCE( 

1971 ASN1F_SEQUENCE_OF( 

1972 "ticketInfo", 

1973 [KrbCredInfo()], 

1974 KrbCredInfo, 

1975 explicit_tag=0xA0, 

1976 ), 

1977 ASN1F_optional( 

1978 UInt32("nonce", None, explicit_tag=0xA1), 

1979 ), 

1980 ASN1F_optional( 

1981 KerberosTime("timestamp", None, explicit_tag=0xA2), 

1982 ), 

1983 ASN1F_optional( 

1984 Microseconds("usec", None, explicit_tag=0xA3), 

1985 ), 

1986 ASN1F_optional( 

1987 ASN1F_PACKET("sAddress", None, HostAddress, explicit_tag=0xA4), 

1988 ), 

1989 ASN1F_optional( 

1990 ASN1F_PACKET("cAddress", None, HostAddress, explicit_tag=0xA5), 

1991 ), 

1992 ), 

1993 implicit_tag=ASN1_Class_KRB.EncKrbCredPart, 

1994 ) 

1995 

1996 

1997# sect 5.9.1 

1998 

1999 

2000class MethodData(ASN1_Packet): 

2001 ASN1_codec = ASN1_Codecs.BER 

2002 ASN1_root = ASN1F_SEQUENCE_OF("seq", [PADATA()], PADATA) 

2003 

2004 

2005class _KRBERROR_data_Field(ASN1F_STRING_PacketField): 

2006 def m2i(self, pkt, s): 

2007 val = super(_KRBERROR_data_Field, self).m2i(pkt, s) 

2008 if not val[0].val: 

2009 return val 

2010 if pkt.errorCode.val in [14, 24, 25, 36]: 

2011 # 14: KDC_ERR_ETYPE_NOSUPP 

2012 # 24: KDC_ERR_PREAUTH_FAILED 

2013 # 25: KDC_ERR_PREAUTH_REQUIRED 

2014 # 36: KRB_AP_ERR_BADMATCH 

2015 return MethodData(val[0].val, _underlayer=pkt), val[1] 

2016 elif pkt.errorCode.val in [6, 7, 12, 13, 18, 29, 41, 60]: 

2017 # 6: KDC_ERR_C_PRINCIPAL_UNKNOWN 

2018 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

2019 # 12: KDC_ERR_POLICY 

2020 # 13: KDC_ERR_BADOPTION 

2021 # 18: KDC_ERR_CLIENT_REVOKED 

2022 # 29: KDC_ERR_SVC_UNAVAILABLE 

2023 # 41: KRB_AP_ERR_MODIFIED 

2024 # 60: KRB_ERR_GENERIC 

2025 try: 

2026 return KERB_ERROR_DATA(val[0].val, _underlayer=pkt), val[1] 

2027 except BER_Decoding_Error: 

2028 if pkt.errorCode.val in [18, 12]: 

2029 # Some types can also happen in FAST sessions 

2030 # 18: KDC_ERR_CLIENT_REVOKED 

2031 return MethodData(val[0].val, _underlayer=pkt), val[1] 

2032 elif pkt.errorCode.val == 7: 

2033 # This looks like an undocumented structure. 

2034 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

2035 return KERB_ERROR_UNK(val[0].val, _underlayer=pkt), val[1] 

2036 raise 

2037 elif pkt.errorCode.val == 69: 

2038 # KRB_AP_ERR_USER_TO_USER_REQUIRED 

2039 return KRB_TGT_REP(val[0].val, _underlayer=pkt), val[1] 

2040 return val 

2041 

2042 

2043class KRB_ERROR(ASN1_Packet): 

2044 ASN1_codec = ASN1_Codecs.BER 

2045 ASN1_root = ASN1F_SEQUENCE( 

2046 ASN1F_SEQUENCE( 

2047 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

2048 ASN1F_enum_INTEGER("msgType", 30, KRB_MSG_TYPES, explicit_tag=0xA1), 

2049 ASN1F_optional( 

2050 KerberosTime("ctime", None, explicit_tag=0xA2), 

2051 ), 

2052 ASN1F_optional( 

2053 Microseconds("cusec", None, explicit_tag=0xA3), 

2054 ), 

2055 KerberosTime("stime", GeneralizedTime(), explicit_tag=0xA4), 

2056 Microseconds("susec", 0, explicit_tag=0xA5), 

2057 ASN1F_enum_INTEGER( 

2058 "errorCode", 

2059 0, 

2060 { 

2061 # RFC4120 sect 7.5.9 

2062 0: "KDC_ERR_NONE", 

2063 1: "KDC_ERR_NAME_EXP", 

2064 2: "KDC_ERR_SERVICE_EXP", 

2065 3: "KDC_ERR_BAD_PVNO", 

2066 4: "KDC_ERR_C_OLD_MAST_KVNO", 

2067 5: "KDC_ERR_S_OLD_MAST_KVNO", 

2068 6: "KDC_ERR_C_PRINCIPAL_UNKNOWN", 

2069 7: "KDC_ERR_S_PRINCIPAL_UNKNOWN", 

2070 8: "KDC_ERR_PRINCIPAL_NOT_UNIQUE", 

2071 9: "KDC_ERR_NULL_KEY", 

2072 10: "KDC_ERR_CANNOT_POSTDATE", 

2073 11: "KDC_ERR_NEVER_VALID", 

2074 12: "KDC_ERR_POLICY", 

2075 13: "KDC_ERR_BADOPTION", 

2076 14: "KDC_ERR_ETYPE_NOSUPP", 

2077 15: "KDC_ERR_SUMTYPE_NOSUPP", 

2078 16: "KDC_ERR_PADATA_TYPE_NOSUPP", 

2079 17: "KDC_ERR_TRTYPE_NOSUPP", 

2080 18: "KDC_ERR_CLIENT_REVOKED", 

2081 19: "KDC_ERR_SERVICE_REVOKED", 

2082 20: "KDC_ERR_TGT_REVOKED", 

2083 21: "KDC_ERR_CLIENT_NOTYET", 

2084 22: "KDC_ERR_SERVICE_NOTYET", 

2085 23: "KDC_ERR_KEY_EXPIRED", 

2086 24: "KDC_ERR_PREAUTH_FAILED", 

2087 25: "KDC_ERR_PREAUTH_REQUIRED", 

2088 26: "KDC_ERR_SERVER_NOMATCH", 

2089 27: "KDC_ERR_MUST_USE_USER2USER", 

2090 28: "KDC_ERR_PATH_NOT_ACCEPTED", 

2091 29: "KDC_ERR_SVC_UNAVAILABLE", 

2092 31: "KRB_AP_ERR_BAD_INTEGRITY", 

2093 32: "KRB_AP_ERR_TKT_EXPIRED", 

2094 33: "KRB_AP_ERR_TKT_NYV", 

2095 34: "KRB_AP_ERR_REPEAT", 

2096 35: "KRB_AP_ERR_NOT_US", 

2097 36: "KRB_AP_ERR_BADMATCH", 

2098 37: "KRB_AP_ERR_SKEW", 

2099 38: "KRB_AP_ERR_BADADDR", 

2100 39: "KRB_AP_ERR_BADVERSION", 

2101 40: "KRB_AP_ERR_MSG_TYPE", 

2102 41: "KRB_AP_ERR_MODIFIED", 

2103 42: "KRB_AP_ERR_BADORDER", 

2104 44: "KRB_AP_ERR_BADKEYVER", 

2105 45: "KRB_AP_ERR_NOKEY", 

2106 46: "KRB_AP_ERR_MUT_FAIL", 

2107 47: "KRB_AP_ERR_BADDIRECTION", 

2108 48: "KRB_AP_ERR_METHOD", 

2109 49: "KRB_AP_ERR_BADSEQ", 

2110 50: "KRB_AP_ERR_INAPP_CKSUM", 

2111 51: "KRB_AP_PATH_NOT_ACCEPTED", 

2112 52: "KRB_ERR_RESPONSE_TOO_BIG", 

2113 60: "KRB_ERR_GENERIC", 

2114 61: "KRB_ERR_FIELD_TOOLONG", 

2115 62: "KDC_ERROR_CLIENT_NOT_TRUSTED", 

2116 63: "KDC_ERROR_KDC_NOT_TRUSTED", 

2117 64: "KDC_ERROR_INVALID_SIG", 

2118 65: "KDC_ERR_KEY_TOO_WEAK", 

2119 66: "KDC_ERR_CERTIFICATE_MISMATCH", 

2120 67: "KRB_AP_ERR_NO_TGT", 

2121 68: "KDC_ERR_WRONG_REALM", 

2122 69: "KRB_AP_ERR_USER_TO_USER_REQUIRED", 

2123 70: "KDC_ERR_CANT_VERIFY_CERTIFICATE", 

2124 71: "KDC_ERR_INVALID_CERTIFICATE", 

2125 72: "KDC_ERR_REVOKED_CERTIFICATE", 

2126 73: "KDC_ERR_REVOCATION_STATUS_UNKNOWN", 

2127 74: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE", 

2128 75: "KDC_ERR_CLIENT_NAME_MISMATCH", 

2129 76: "KDC_ERR_KDC_NAME_MISMATCH", 

2130 # draft-ietf-kitten-iakerb 

2131 85: "KRB_AP_ERR_IAKERB_KDC_NOT_FOUND", 

2132 86: "KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE", 

2133 # RFC6113 

2134 90: "KDC_ERR_PREAUTH_EXPIRED", 

2135 91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED", 

2136 92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET", 

2137 93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS", 

2138 # RFC8636 

2139 100: "KDC_ERR_NO_ACCEPTABLE_KDF", 

2140 }, 

2141 explicit_tag=0xA6, 

2142 ), 

2143 ASN1F_optional(Realm("crealm", None, explicit_tag=0xA7)), 

2144 ASN1F_optional( 

2145 ASN1F_PACKET("cname", None, PrincipalName, explicit_tag=0xA8), 

2146 ), 

2147 Realm("realm", "", explicit_tag=0xA9), 

2148 ASN1F_PACKET("sname", PrincipalName(), PrincipalName, explicit_tag=0xAA), 

2149 ASN1F_optional(KerberosString("eText", "", explicit_tag=0xAB)), 

2150 ASN1F_optional(_KRBERROR_data_Field("eData", "", explicit_tag=0xAC)), 

2151 ), 

2152 implicit_tag=ASN1_Class_KRB.ERROR, 

2153 ) 

2154 

2155 def getSPN(self): 

2156 return "%s@%s" % ( 

2157 self.sname.toString(), 

2158 self.realm.val.decode(), 

2159 ) 

2160 

2161 

2162# PA-FX-ERROR 

2163_PADATA_CLASSES[137] = KRB_ERROR 

2164 

2165 

2166# [MS-KILE] sect 2.2.1 

2167 

2168 

2169class KERB_EXT_ERROR(Packet): 

2170 fields_desc = [ 

2171 XLEIntEnumField("status", 0, STATUS_ERREF), 

2172 XLEIntField("reserved", 0), 

2173 XLEIntField("flags", 0x00000001), 

2174 ] 

2175 

2176 

2177# [MS-KILE] sect 2.2.2 

2178 

2179 

2180class _Error_Field(ASN1F_STRING_PacketField): 

2181 def m2i(self, pkt, s): 

2182 val = super(_Error_Field, self).m2i(pkt, s) 

2183 if not val[0].val: 

2184 return val 

2185 if pkt.dataType.val == 3: # KERB_ERR_TYPE_EXTENDED 

2186 return KERB_EXT_ERROR(val[0].val, _underlayer=pkt), val[1] 

2187 return val 

2188 

2189 

2190class KERB_ERROR_DATA(ASN1_Packet): 

2191 ASN1_codec = ASN1_Codecs.BER 

2192 ASN1_root = ASN1F_SEQUENCE( 

2193 ASN1F_enum_INTEGER( 

2194 "dataType", 

2195 2, 

2196 { 

2197 1: "KERB_AP_ERR_TYPE_NTSTATUS", # from the wdk 

2198 2: "KERB_AP_ERR_TYPE_SKEW_RECOVERY", 

2199 3: "KERB_ERR_TYPE_EXTENDED", 

2200 }, 

2201 explicit_tag=0xA1, 

2202 ), 

2203 ASN1F_optional(_Error_Field("dataValue", None, explicit_tag=0xA2)), 

2204 ) 

2205 

2206 

2207# This looks like an undocumented structure. 

2208 

2209 

2210class KERB_ERROR_UNK(ASN1_Packet): 

2211 ASN1_codec = ASN1_Codecs.BER 

2212 ASN1_root = ASN1F_SEQUENCE( 

2213 ASN1F_SEQUENCE( 

2214 ASN1F_enum_INTEGER( 

2215 "dataType", 

2216 0, 

2217 { 

2218 -128: "KDC_ERR_MUST_USE_USER2USER", 

2219 }, 

2220 explicit_tag=0xA0, 

2221 ), 

2222 ASN1F_STRING("dataValue", None, explicit_tag=0xA1), 

2223 ) 

2224 ) 

2225 

2226 

2227# Kerberos U2U - draft-ietf-cat-user2user-03 

2228 

2229 

2230class KRB_TGT_REQ(ASN1_Packet): 

2231 ASN1_codec = ASN1_Codecs.BER 

2232 ASN1_root = ASN1F_SEQUENCE( 

2233 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

2234 ASN1F_enum_INTEGER("msgType", 16, KRB_MSG_TYPES, explicit_tag=0xA1), 

2235 ASN1F_optional( 

2236 ASN1F_PACKET("sname", None, PrincipalName, explicit_tag=0xA2), 

2237 ), 

2238 ASN1F_optional( 

2239 Realm("realm", None, explicit_tag=0xA3), 

2240 ), 

2241 ) 

2242 

2243 

2244class KRB_TGT_REP(ASN1_Packet): 

2245 ASN1_codec = ASN1_Codecs.BER 

2246 ASN1_root = ASN1F_SEQUENCE( 

2247 ASN1F_INTEGER("pvno", 5, explicit_tag=0xA0), 

2248 ASN1F_enum_INTEGER("msgType", 17, KRB_MSG_TYPES, explicit_tag=0xA1), 

2249 ASN1F_PACKET("ticket", None, KRB_Ticket, explicit_tag=0xA2), 

2250 ) 

2251 

2252 

2253# draft-ietf-kitten-iakerb-03 sect 4 

2254 

2255 

2256class KRB_FINISHED(ASN1_Packet): 

2257 ASN1_codec = ASN1_Codecs.BER 

2258 ASN1_root = ASN1F_SEQUENCE( 

2259 ASN1F_PACKET("gssMic", Checksum(), Checksum, explicit_tag=0xA1), 

2260 ) 

2261 

2262 

2263# RFC 6542 sect 3.1 

2264 

2265 

2266class KRB_GSS_EXT(Packet): 

2267 fields_desc = [ 

2268 IntEnumField( 

2269 "type", 

2270 0, 

2271 { 

2272 # https://www.iana.org/assignments/kerberos-v-gss-api/kerberos-v-gss-api.xhtml 

2273 0x00000000: "GSS_EXTS_CHANNEL_BINDING", # RFC 6542 sect 3.2 

2274 0x00000001: "GSS_EXTS_IAKERB_FINISHED", # not standard 

2275 0x00000002: "GSS_EXTS_FINISHED", # PKU2U / IAKERB 

2276 }, 

2277 ), 

2278 FieldLenField("length", None, length_of="data", fmt="!I"), 

2279 MultipleTypeField( 

2280 [ 

2281 ( 

2282 PacketField("data", KRB_FINISHED(), KRB_FINISHED), 

2283 lambda pkt: pkt.type == 0x00000002, 

2284 ), 

2285 ], 

2286 XStrLenField("data", b"", length_from=lambda pkt: pkt.length), 

2287 ), 

2288 ] 

2289 

2290 

2291# RFC 4121 sect 4.1.1 

2292 

2293 

2294class KRB_AuthenticatorChecksum(Packet): 

2295 fields_desc = [ 

2296 FieldLenField("Lgth", None, length_of="Bnd", fmt="<I"), 

2297 XStrLenField("Bnd", b"\x00" * 16, length_from=lambda pkt: pkt.Lgth), 

2298 FlagsField( 

2299 "Flags", 

2300 0, 

2301 -32, 

2302 { 

2303 0x01: "GSS_C_DELEG_FLAG", 

2304 0x02: "GSS_C_MUTUAL_FLAG", 

2305 0x04: "GSS_C_REPLAY_FLAG", 

2306 0x08: "GSS_C_SEQUENCE_FLAG", 

2307 0x10: "GSS_C_CONF_FLAG", # confidentiality 

2308 0x20: "GSS_C_INTEG_FLAG", # integrity 

2309 # RFC4757 

2310 0x1000: "GSS_C_DCE_STYLE", 

2311 0x2000: "GSS_C_IDENTIFY_FLAG", 

2312 0x4000: "GSS_C_EXTENDED_ERROR_FLAG", 

2313 }, 

2314 ), 

2315 ConditionalField( 

2316 LEShortField("DlgOpt", 0), 

2317 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2318 ), 

2319 ConditionalField( 

2320 FieldLenField("Dlgth", None, length_of="Deleg"), 

2321 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2322 ), 

2323 ConditionalField( 

2324 PacketLenField( 

2325 "Deleg", KRB_CRED(), KRB_CRED, length_from=lambda pkt: pkt.Dlgth 

2326 ), 

2327 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2328 ), 

2329 # Extensions: RFC 6542 sect 3.1 

2330 PacketListField("Exts", KRB_GSS_EXT(), KRB_GSS_EXT), 

2331 ] 

2332 

2333 

2334# Kerberos V5 GSS-API - RFC1964 and RFC4121 

2335 

2336_TOK_IDS = { 

2337 # RFC 1964 

2338 b"\x01\x00": "KRB-AP-REQ", 

2339 b"\x02\x00": "KRB-AP-REP", 

2340 b"\x03\x00": "KRB-ERROR", 

2341 b"\x01\x01": "GSS_GetMIC-RFC1964", 

2342 b"\x02\x01": "GSS_Wrap-RFC1964", 

2343 b"\x01\x02": "GSS_Delete_sec_context-RFC1964", 

2344 # U2U: [draft-ietf-cat-user2user-03] 

2345 b"\x04\x00": "KRB-TGT-REQ", 

2346 b"\x04\x01": "KRB-TGT-REP", 

2347 # RFC 4121 

2348 b"\x04\x04": "GSS_GetMIC", 

2349 b"\x05\x04": "GSS_Wrap", 

2350 # IAKERB: [draft-ietf-kitten-iakerb-03] 

2351 b"\x05\x01": "IAKERB_PROXY", 

2352} 

2353_SGN_ALGS = { 

2354 0x00: "DES MAC MD5", 

2355 0x01: "MD2.5", 

2356 0x02: "DES MAC", 

2357 # RFC 4757 

2358 0x11: "HMAC", 

2359} 

2360_SEAL_ALGS = { 

2361 0: "DES", 

2362 0xFFFF: "none", 

2363 # RFC 4757 

2364 0x10: "RC4", 

2365} 

2366 

2367 

2368# RFC 1964 - sect 1.1 

2369 

2370# See https://www.iana.org/assignments/kerberos-v-gss-api/kerberos-v-gss-api.xhtml 

2371_InitialContextTokens = {} # filled below 

2372 

2373 

2374class KRB_InnerToken(Packet): 

2375 name = "Kerberos v5 InnerToken" 

2376 fields_desc = [ 

2377 StrFixedLenEnumField("TOK_ID", b"\x01\x00", _TOK_IDS, length=2), 

2378 PacketField( 

2379 "root", 

2380 KRB_AP_REQ(), 

2381 lambda x, _parent: _InitialContextTokens[_parent.TOK_ID](x), 

2382 ), 

2383 ] 

2384 

2385 def mysummary(self): 

2386 return self.sprintf( 

2387 "Kerberos %s" % _TOK_IDS.get(self.TOK_ID, repr(self.TOK_ID)) 

2388 ) 

2389 

2390 def guess_payload_class(self, payload): 

2391 if self.TOK_ID in [b"\x01\x01", b"\x02\x01", b"\x04\x04", b"\x05\x04"]: 

2392 return conf.padding_layer 

2393 return Kerberos 

2394 

2395 @classmethod 

2396 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

2397 if _pkt and len(_pkt) >= 13: 

2398 # Older RFC1964 variants of the token have KRB_GSSAPI_Token wrapper 

2399 if _pkt[2:13] == b"\x06\t*\x86H\x86\xf7\x12\x01\x02\x02": 

2400 return KRB_GSSAPI_Token 

2401 return cls 

2402 

2403 

2404# RFC 4121 - sect 4.1 

2405 

2406 

2407class KRB_GSSAPI_Token(GSSAPI_BLOB): 

2408 name = "Kerberos GSSAPI-Token" 

2409 ASN1_codec = ASN1_Codecs.BER 

2410 ASN1_root = ASN1F_SEQUENCE( 

2411 ASN1F_OID("MechType", "1.2.840.113554.1.2.2"), 

2412 ASN1F_PACKET( 

2413 "innerToken", 

2414 KRB_InnerToken(), 

2415 KRB_InnerToken, 

2416 implicit_tag=0x0, 

2417 ), 

2418 implicit_tag=ASN1_Class_KRB.Token, 

2419 ) 

2420 

2421 

2422# RFC 1964 - sect 1.2.1 

2423 

2424 

2425class KRB_GSS_MIC_RFC1964(Packet): 

2426 name = "Kerberos v5 MIC Token (RFC1964)" 

2427 fields_desc = [ 

2428 LEShortEnumField("SGN_ALG", 0, _SGN_ALGS), 

2429 XLEIntField("Filler", 0xFFFFFFFF), 

2430 XStrFixedLenField("SND_SEQ", b"", length=8), 

2431 PadField( # sect 1.2.2.3 

2432 XStrFixedLenField("SGN_CKSUM", b"", length=8), 

2433 align=8, 

2434 padwith=b"\x04", 

2435 ), 

2436 ] 

2437 

2438 def default_payload_class(self, payload): 

2439 return conf.padding_layer 

2440 

2441 

2442_InitialContextTokens[b"\x01\x01"] = KRB_GSS_MIC_RFC1964 

2443 

2444# RFC 1964 - sect 1.2.2 

2445 

2446 

2447class KRB_GSS_Wrap_RFC1964(Packet): 

2448 name = "Kerberos v5 GSS_Wrap (RFC1964)" 

2449 fields_desc = [ 

2450 LEShortEnumField("SGN_ALG", 0, _SGN_ALGS), 

2451 LEShortEnumField("SEAL_ALG", 0, _SEAL_ALGS), 

2452 XLEShortField("Filler", 0xFFFF), 

2453 XStrFixedLenField("SND_SEQ", b"", length=8), 

2454 PadField( # sect 1.2.2.3 

2455 XStrFixedLenField("SGN_CKSUM", b"", length=8), 

2456 align=8, 

2457 padwith=b"\x04", 

2458 ), 

2459 # sect 1.2.2.3 

2460 XStrFixedLenField("CONFOUNDER", b"", length=8), 

2461 ] 

2462 

2463 def default_payload_class(self, payload): 

2464 return conf.padding_layer 

2465 

2466 

2467_InitialContextTokens[b"\x02\x01"] = KRB_GSS_Wrap_RFC1964 

2468 

2469 

2470# RFC 1964 - sect 1.2.2 

2471 

2472 

2473class KRB_GSS_Delete_sec_context_RFC1964(Packet): 

2474 name = "Kerberos v5 GSS_Delete_sec_context (RFC1964)" 

2475 fields_desc = KRB_GSS_MIC_RFC1964.fields_desc 

2476 

2477 

2478_InitialContextTokens[b"\x01\x02"] = KRB_GSS_Delete_sec_context_RFC1964 

2479 

2480 

2481# RFC 4121 - sect 4.2.2 

2482_KRB5_GSS_Flags = [ 

2483 "SentByAcceptor", 

2484 "Sealed", 

2485 "AcceptorSubkey", 

2486] 

2487 

2488 

2489# RFC 4121 - sect 4.2.6.1 

2490 

2491 

2492class KRB_GSS_MIC(Packet): 

2493 name = "Kerberos v5 MIC Token" 

2494 fields_desc = [ 

2495 FlagsField("Flags", 0, 8, _KRB5_GSS_Flags), 

2496 XStrFixedLenField("Filler", b"\xff\xff\xff\xff\xff", length=5), 

2497 LongField("SND_SEQ", 0), # Big endian 

2498 XStrField("SGN_CKSUM", b"\x00" * 12), 

2499 ] 

2500 

2501 def default_payload_class(self, payload): 

2502 return conf.padding_layer 

2503 

2504 

2505_InitialContextTokens[b"\x04\x04"] = KRB_GSS_MIC 

2506 

2507 

2508# RFC 4121 - sect 4.2.6.2 

2509 

2510 

2511class KRB_GSS_Wrap(Packet): 

2512 name = "Kerberos v5 Wrap Token" 

2513 fields_desc = [ 

2514 FlagsField("Flags", 0, 8, _KRB5_GSS_Flags), 

2515 XByteField("Filler", 0xFF), 

2516 ShortField("EC", 0), # Big endian 

2517 ShortField("RRC", 0), # Big endian 

2518 LongField("SND_SEQ", 0), # Big endian 

2519 MultipleTypeField( 

2520 [ 

2521 ( 

2522 XStrField("Data", b""), 

2523 lambda pkt: pkt.Flags.Sealed, 

2524 ) 

2525 ], 

2526 XStrLenField("Data", b"", length_from=lambda pkt: pkt.EC), 

2527 ), 

2528 ] 

2529 

2530 def default_payload_class(self, payload): 

2531 return conf.padding_layer 

2532 

2533 

2534_InitialContextTokens[b"\x05\x04"] = KRB_GSS_Wrap 

2535 

2536 

2537# Kerberos IAKERB - draft-ietf-kitten-iakerb-03 

2538 

2539 

2540class IAKERB_HEADER(ASN1_Packet): 

2541 ASN1_codec = ASN1_Codecs.BER 

2542 ASN1_root = ASN1F_SEQUENCE( 

2543 Realm("targetRealm", "", explicit_tag=0xA1), 

2544 ASN1F_optional( 

2545 ASN1F_STRING("cookie", None, explicit_tag=0xA2), 

2546 ), 

2547 ) 

2548 

2549 

2550_InitialContextTokens[b"\x05\x01"] = IAKERB_HEADER 

2551 

2552 

2553# Register for GSSAPI 

2554 

2555# Kerberos 5 

2556_GSSAPI_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2557_GSSAPI_SIGNATURE_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2558# Kerberos 5 - U2U 

2559_GSSAPI_OIDS["1.2.840.113554.1.2.2.3"] = KRB_InnerToken 

2560# Kerberos 5 - IAKERB 

2561_GSSAPI_OIDS["1.3.6.1.5.2.5"] = KRB_InnerToken 

2562 

2563 

2564# Entry class 

2565 

2566# RFC4120 sect 5.10 

2567 

2568 

2569class Kerberos(ASN1_Packet): 

2570 ASN1_codec = ASN1_Codecs.BER 

2571 ASN1_root = ASN1F_CHOICE( 

2572 "root", 

2573 None, 

2574 # RFC4120 

2575 KRB_GSSAPI_Token, # [APPLICATION 0] 

2576 KRB_Ticket, # [APPLICATION 1] 

2577 KRB_Authenticator, # [APPLICATION 2] 

2578 KRB_AS_REQ, # [APPLICATION 10] 

2579 KRB_AS_REP, # [APPLICATION 11] 

2580 KRB_TGS_REQ, # [APPLICATION 12] 

2581 KRB_TGS_REP, # [APPLICATION 13] 

2582 KRB_AP_REQ, # [APPLICATION 14] 

2583 KRB_AP_REP, # [APPLICATION 15] 

2584 # RFC4120 

2585 KRB_ERROR, # [APPLICATION 30] 

2586 ) 

2587 

2588 def mysummary(self): 

2589 return self.root.summary() 

2590 

2591 

2592bind_bottom_up(UDP, Kerberos, sport=88) 

2593bind_bottom_up(UDP, Kerberos, dport=88) 

2594bind_layers(UDP, Kerberos, sport=88, dport=88) 

2595 

2596_InitialContextTokens[b"\x01\x00"] = KRB_AP_REQ 

2597_InitialContextTokens[b"\x02\x00"] = KRB_AP_REP 

2598_InitialContextTokens[b"\x03\x00"] = KRB_ERROR 

2599_InitialContextTokens[b"\x04\x00"] = KRB_TGT_REQ 

2600_InitialContextTokens[b"\x04\x01"] = KRB_TGT_REP 

2601 

2602 

2603# RFC4120 sect 7.2.2 

2604 

2605 

2606class KerberosTCPHeader(Packet): 

2607 # According to RFC 5021, first bit to 1 has a special meaning and 

2608 # negotiates Kerberos TCP extensions... But apart from rfc6251 no one used that 

2609 # https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-4 

2610 fields_desc = [LenField("len", None, fmt="!I")] 

2611 

2612 @classmethod 

2613 def tcp_reassemble(cls, data, *args, **kwargs): 

2614 if len(data) < 4: 

2615 return None 

2616 length = struct.unpack("!I", data[:4])[0] 

2617 if len(data) == length + 4: 

2618 return cls(data) 

2619 

2620 

2621bind_layers(KerberosTCPHeader, Kerberos) 

2622 

2623bind_bottom_up(TCP, KerberosTCPHeader, sport=88) 

2624bind_layers(TCP, KerberosTCPHeader, dport=88) 

2625 

2626 

2627# RFC3244 sect 2 

2628 

2629 

2630class KPASSWD_REQ(Packet): 

2631 fields_desc = [ 

2632 ShortField("len", None), 

2633 ShortField("pvno", 0xFF80), 

2634 ShortField("apreqlen", None), 

2635 PacketLenField( 

2636 "apreq", KRB_AP_REQ(), KRB_AP_REQ, length_from=lambda pkt: pkt.apreqlen 

2637 ), 

2638 ConditionalField( 

2639 PacketLenField( 

2640 "krbpriv", 

2641 KRB_PRIV(), 

2642 KRB_PRIV, 

2643 length_from=lambda pkt: pkt.len - 6 - pkt.apreqlen, 

2644 ), 

2645 lambda pkt: pkt.apreqlen != 0, 

2646 ), 

2647 ConditionalField( 

2648 PacketLenField( 

2649 "error", KRB_ERROR(), KRB_ERROR, length_from=lambda pkt: pkt.len - 6 

2650 ), 

2651 lambda pkt: pkt.apreqlen == 0, 

2652 ), 

2653 ] 

2654 

2655 def post_build(self, p, pay): 

2656 if self.len is None: 

2657 p = struct.pack("!H", len(p)) + p[2:] 

2658 if self.apreqlen is None and self.krbpriv is not None: 

2659 p = p[:4] + struct.pack("!H", len(self.apreq)) + p[6:] 

2660 return p + pay 

2661 

2662 

2663class ChangePasswdData(ASN1_Packet): 

2664 ASN1_codec = ASN1_Codecs.BER 

2665 ASN1_root = ASN1F_SEQUENCE( 

2666 ASN1F_STRING("newpasswd", ASN1_STRING(""), explicit_tag=0xA0), 

2667 ASN1F_optional( 

2668 ASN1F_PACKET("targname", None, PrincipalName, explicit_tag=0xA1) 

2669 ), 

2670 ASN1F_optional(Realm("targrealm", None, explicit_tag=0xA2)), 

2671 ) 

2672 

2673 

2674class KPASSWD_REP(Packet): 

2675 fields_desc = [ 

2676 ShortField("len", None), 

2677 ShortField("pvno", 0x0001), 

2678 ShortField("apreplen", None), 

2679 PacketLenField( 

2680 "aprep", KRB_AP_REP(), KRB_AP_REP, length_from=lambda pkt: pkt.apreplen 

2681 ), 

2682 ConditionalField( 

2683 PacketLenField( 

2684 "krbpriv", 

2685 KRB_PRIV(), 

2686 KRB_PRIV, 

2687 length_from=lambda pkt: pkt.len - 6 - pkt.apreplen, 

2688 ), 

2689 lambda pkt: pkt.apreplen != 0, 

2690 ), 

2691 ConditionalField( 

2692 PacketLenField( 

2693 "error", KRB_ERROR(), KRB_ERROR, length_from=lambda pkt: pkt.len - 6 

2694 ), 

2695 lambda pkt: pkt.apreplen == 0, 

2696 ), 

2697 ] 

2698 

2699 def post_build(self, p, pay): 

2700 if self.len is None: 

2701 p = struct.pack("!H", len(p)) + p[2:] 

2702 if self.apreplen is None and self.krbpriv is not None: 

2703 p = p[:4] + struct.pack("!H", len(self.aprep)) + p[6:] 

2704 return p + pay 

2705 

2706 def answers(self, other): 

2707 return isinstance(other, KPASSWD_REQ) 

2708 

2709 

2710KPASSWD_RESULTS = { 

2711 0: "KRB5_KPASSWD_SUCCESS", 

2712 1: "KRB5_KPASSWD_MALFORMED", 

2713 2: "KRB5_KPASSWD_HARDERROR", 

2714 3: "KRB5_KPASSWD_AUTHERROR", 

2715 4: "KRB5_KPASSWD_SOFTERROR", 

2716 5: "KRB5_KPASSWD_ACCESSDENIED", 

2717 6: "KRB5_KPASSWD_BAD_VERSION", 

2718 7: "KRB5_KPASSWD_INITIAL_FLAG_NEEDED", 

2719} 

2720 

2721 

2722class KPasswdRepData(Packet): 

2723 fields_desc = [ 

2724 ShortEnumField("resultCode", 0, KPASSWD_RESULTS), 

2725 StrField("resultString", ""), 

2726 ] 

2727 

2728 

2729class Kpasswd(Packet): 

2730 @classmethod 

2731 def dispatch_hook(cls, _pkt=None, *args, **kargs): 

2732 if _pkt and len(_pkt) >= 4: 

2733 if _pkt[2:4] == b"\xff\x80": 

2734 return KPASSWD_REQ 

2735 elif _pkt[2:4] == b"\x00\x01": 

2736 asn1_tag = BER_id_dec(_pkt[6:8])[0] & 0x1F 

2737 if asn1_tag == 14: 

2738 return KPASSWD_REQ 

2739 elif asn1_tag == 15: 

2740 return KPASSWD_REP 

2741 return KPASSWD_REQ 

2742 

2743 

2744bind_bottom_up(UDP, Kpasswd, sport=464) 

2745bind_bottom_up(UDP, Kpasswd, dport=464) 

2746bind_top_down(UDP, KPASSWD_REQ, sport=464, dport=464) 

2747bind_top_down(UDP, KPASSWD_REP, sport=464, dport=464) 

2748 

2749 

2750class KpasswdTCPHeader(Packet): 

2751 fields_desc = [LenField("len", None, fmt="!I")] 

2752 

2753 @classmethod 

2754 def tcp_reassemble(cls, data, *args, **kwargs): 

2755 if len(data) < 4: 

2756 return None 

2757 length = struct.unpack("!I", data[:4])[0] 

2758 if len(data) == length + 4: 

2759 return cls(data) 

2760 

2761 

2762bind_layers(KpasswdTCPHeader, Kpasswd) 

2763 

2764bind_bottom_up(TCP, KpasswdTCPHeader, sport=464) 

2765bind_layers(TCP, KpasswdTCPHeader, dport=464) 

2766 

2767# [MS-KKDCP] 

2768 

2769 

2770class _KerbMessage_Field(ASN1F_STRING_PacketField): 

2771 def m2i(self, pkt, s): 

2772 val = super(_KerbMessage_Field, self).m2i(pkt, s) 

2773 if not val[0].val: 

2774 return val 

2775 return KerberosTCPHeader(val[0].val, _underlayer=pkt), val[1] 

2776 

2777 

2778class KDC_PROXY_MESSAGE(ASN1_Packet): 

2779 ASN1_codec = ASN1_Codecs.BER 

2780 ASN1_root = ASN1F_SEQUENCE( 

2781 _KerbMessage_Field("kerbMessage", "", explicit_tag=0xA0), 

2782 ASN1F_optional(Realm("targetDomain", None, explicit_tag=0xA1)), 

2783 ASN1F_optional( 

2784 ASN1F_FLAGS( 

2785 "dclocatorHint", 

2786 None, 

2787 FlagsField("", 0, -32, _NV_VERSION).names, 

2788 explicit_tag=0xA2, 

2789 ) 

2790 ), 

2791 ) 

2792 

2793 

2794class KdcProxySocket(SuperSocket): 

2795 """ 

2796 This is a wrapper of a HTTP_Client that does KKDCP proxying, 

2797 disguised as a SuperSocket to be compatible with the rest of the KerberosClient. 

2798 """ 

2799 

2800 def __init__( 

2801 self, 

2802 url, 

2803 targetDomain, 

2804 dclocatorHint=None, 

2805 no_check_certificate=False, 

2806 **kwargs, 

2807 ): 

2808 self.url = url 

2809 self.targetDomain = targetDomain 

2810 self.dclocatorHint = dclocatorHint 

2811 self.no_check_certificate = no_check_certificate 

2812 self.queue = deque() 

2813 super(KdcProxySocket, self).__init__(**kwargs) 

2814 

2815 def recv(self, x=None): 

2816 return self.queue.popleft() 

2817 

2818 def send(self, x, **kwargs): 

2819 from scapy.layers.http import HTTP_Client 

2820 

2821 cli = HTTP_Client(no_check_certificate=self.no_check_certificate) 

2822 try: 

2823 # sr it via the web client 

2824 resp = cli.request( 

2825 self.url, 

2826 Method="POST", 

2827 data=bytes( 

2828 # Wrap request in KDC_PROXY_MESSAGE 

2829 KDC_PROXY_MESSAGE( 

2830 kerbMessage=bytes(x), 

2831 targetDomain=ASN1_GENERAL_STRING(self.targetDomain.encode()), 

2832 # dclocatorHint is optional 

2833 dclocatorHint=self.dclocatorHint, 

2834 ) 

2835 ), 

2836 http_headers={ 

2837 "Cache-Control": "no-cache", 

2838 "Pragma": "no-cache", 

2839 "User-Agent": "kerberos/1.0", 

2840 }, 

2841 ) 

2842 if resp and conf.raw_layer in resp: 

2843 # Parse the payload 

2844 resp = KDC_PROXY_MESSAGE(resp.load).kerbMessage 

2845 # We have an answer, queue it. 

2846 self.queue.append(resp) 

2847 else: 

2848 raise EOFError 

2849 finally: 

2850 cli.close() 

2851 

2852 @staticmethod 

2853 def select(sockets, remain=None): 

2854 return [x for x in sockets if isinstance(x, KdcProxySocket) and x.queue] 

2855 

2856 

2857# Util functions 

2858 

2859 

2860class KerberosClient(Automaton): 

2861 """ 

2862 Implementation of a Kerberos client. 

2863 

2864 Prefer to use the ``krb_as_req`` and ``krb_tgs_req`` functions which 

2865 wrap this client. 

2866 

2867 Common parameters: 

2868 

2869 :param mode: the mode to use for the client (default: AS_REQ). 

2870 :param ip: the IP of the DC (default: discovered by dclocator) 

2871 :param upn: the UPN of the client. 

2872 :param password: the password of the client. 

2873 :param key: the Key of the client (instead of the password) 

2874 :param realm: the realm of the domain. (default: from the UPN) 

2875 :param host: the name of the host doing the request 

2876 :param port: the Kerberos port (default 88) 

2877 :param timeout: timeout of each request (default 5) 

2878 

2879 Advanced common parameters: 

2880 

2881 :param kdc_proxy: specify a KDC proxy url 

2882 :param kdc_proxy_no_check_certificate: do not check the KDC proxy certificate 

2883 :param fast: use FAST armoring 

2884 :param armor_ticket: an external ticket to use for armoring 

2885 :param armor_ticket_upn: the UPN of the client of the armoring ticket 

2886 :param armor_ticket_skey: the session Key object of the armoring ticket 

2887 :param etypes: specify the list of encryption types to support 

2888 

2889 AS-REQ only: 

2890 

2891 :param x509: a X509 certificate to use for PKINIT AS_REQ or S4U2Proxy 

2892 :param x509key: the private key of the X509 certificate (in an AS_REQ) 

2893 :param p12: (optional) use a pfx/p12 instead of x509 and x509key. In this case, 

2894 'password' is the password of the p12. 

2895 

2896 TGS-REQ only: 

2897 

2898 :param spn: the SPN to request in a TGS-REQ 

2899 :param ticket: the existing ticket to use in a TGS-REQ 

2900 :param renew: sets the Renew flag in a TGS-REQ 

2901 :param additional_tickets: in U2U or S4U2Proxy, the additional tickets 

2902 :param u2u: sets the U2U flag 

2903 :param for_user: the UPN of another user in TGS-REQ, to do a S4U2Self 

2904 :param s4u2proxy: sets the S4U2Proxy flag 

2905 :param dmsa: sets the 'unconditional delegation' mode for DMSA TGT retrieval 

2906 """ 

2907 

2908 RES_AS_MODE = namedtuple("AS_Result", ["asrep", "sessionkey", "kdcrep"]) 

2909 RES_TGS_MODE = namedtuple("TGS_Result", ["tgsrep", "sessionkey", "kdcrep"]) 

2910 

2911 class MODE(IntEnum): 

2912 AS_REQ = 0 

2913 TGS_REQ = 1 

2914 GET_SALT = 2 

2915 

2916 def __init__( 

2917 self, 

2918 mode=MODE.AS_REQ, 

2919 ip=None, 

2920 upn=None, 

2921 password=None, 

2922 key=None, 

2923 realm=None, 

2924 x509=None, 

2925 x509key=None, 

2926 p12=None, 

2927 spn=None, 

2928 ticket=None, 

2929 host=None, 

2930 renew=False, 

2931 additional_tickets=[], 

2932 u2u=False, 

2933 for_user=None, 

2934 s4u2proxy=False, 

2935 dmsa=False, 

2936 kdc_proxy=None, 

2937 kdc_proxy_no_check_certificate=False, 

2938 fast=False, 

2939 armor_ticket=None, 

2940 armor_ticket_upn=None, 

2941 armor_ticket_skey=None, 

2942 key_list_req=[], 

2943 etypes=None, 

2944 port=88, 

2945 timeout=5, 

2946 **kwargs, 

2947 ): 

2948 import scapy.libs.rfc3961 # Trigger error if any # noqa: F401 

2949 from scapy.layers.ldap import dclocator 

2950 

2951 if not upn: 

2952 raise ValueError("Invalid upn") 

2953 if not spn: 

2954 raise ValueError("Invalid spn") 

2955 if realm is None: 

2956 if mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]: 

2957 _, realm = _parse_upn(upn) 

2958 elif mode == self.MODE.TGS_REQ: 

2959 _, realm = _parse_spn(spn) 

2960 if not realm and ticket: 

2961 # if no realm is specified, but there's a ticket, take the realm 

2962 # of the ticket. 

2963 realm = ticket.realm.val.decode() 

2964 else: 

2965 raise ValueError("Invalid realm") 

2966 

2967 # PKINIT checks 

2968 if p12 is not None: 

2969 from cryptography.hazmat.primitives.serialization import pkcs12 

2970 

2971 # password should be None or bytes 

2972 if isinstance(password, str): 

2973 password = password.encode() 

2974 

2975 # Read p12/pfx 

2976 with open(p12, "rb") as fd: 

2977 x509key, x509, _ = pkcs12.load_key_and_certificates( 

2978 fd.read(), 

2979 password=password, 

2980 ) 

2981 x509 = Cert(cryptography_obj=x509) 

2982 x509key = PrivKey(cryptography_obj=x509key) 

2983 elif x509 and x509key: 

2984 x509 = Cert(x509) 

2985 x509key = PrivKey(x509key) 

2986 

2987 if mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]: 

2988 if not host: 

2989 raise ValueError("Invalid host") 

2990 if (x509 is None) ^ (x509key is None): 

2991 raise ValueError("Must provide both 'x509' and 'x509key' !") 

2992 elif mode == self.MODE.TGS_REQ: 

2993 if not ticket: 

2994 raise ValueError("Invalid ticket") 

2995 

2996 if not ip and not kdc_proxy: 

2997 # No KDC IP provided. Find it by querying the DNS 

2998 ip = dclocator( 

2999 realm, 

3000 timeout=timeout, 

3001 # Use connect mode instead of ldap for compatibility 

3002 # with MIT kerberos servers 

3003 mode="connect", 

3004 port=port, 

3005 debug=kwargs.get("debug", 0), 

3006 ).ip 

3007 

3008 # Armoring checks 

3009 if fast: 

3010 if mode == self.MODE.AS_REQ: 

3011 # Requires an external ticket 

3012 if not armor_ticket or not armor_ticket_upn or not armor_ticket_skey: 

3013 raise ValueError( 

3014 "Implicit armoring is not possible on AS-REQ: " 

3015 "please provide the 3 required armor arguments" 

3016 ) 

3017 elif mode == self.MODE.TGS_REQ: 

3018 if armor_ticket and (not armor_ticket_upn or not armor_ticket_skey): 

3019 raise ValueError( 

3020 "Cannot specify armor_ticket without armor_ticket_{upn,skey}" 

3021 ) 

3022 

3023 if mode == self.MODE.GET_SALT: 

3024 if etypes is not None: 

3025 raise ValueError("Cannot specify etypes in GET_SALT mode !") 

3026 

3027 from scapy.libs.rfc3961 import EncryptionType 

3028 

3029 etypes = [ 

3030 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3031 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3032 ] 

3033 elif etypes is None: 

3034 from scapy.libs.rfc3961 import EncryptionType 

3035 

3036 etypes = [ 

3037 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3038 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3039 EncryptionType.RC4_HMAC, 

3040 EncryptionType.RC4_HMAC_EXP, 

3041 EncryptionType.DES_CBC_MD5, 

3042 ] 

3043 self.etypes = etypes 

3044 

3045 self.mode = mode 

3046 

3047 self.result = None # Result 

3048 

3049 self._timeout = timeout 

3050 self._ip = ip 

3051 self._port = port 

3052 self.kdc_proxy = kdc_proxy 

3053 self.kdc_proxy_no_check_certificate = kdc_proxy_no_check_certificate 

3054 

3055 if self.mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]: 

3056 self.host = host.upper() 

3057 self.password = password and bytes_encode(password) 

3058 self.spn = spn 

3059 self.upn = upn 

3060 self.realm = realm.upper() 

3061 self.x509 = x509 

3062 self.x509key = x509key 

3063 self.ticket = ticket 

3064 self.fast = fast 

3065 self.armor_ticket = armor_ticket 

3066 self.armor_ticket_upn = armor_ticket_upn 

3067 self.armor_ticket_skey = armor_ticket_skey 

3068 self.key_list_req = key_list_req 

3069 self.renew = renew 

3070 self.additional_tickets = additional_tickets # U2U + S4U2Proxy 

3071 self.u2u = u2u # U2U 

3072 self.for_user = for_user # FOR-USER 

3073 self.s4u2proxy = s4u2proxy # S4U2Proxy 

3074 self.dmsa = dmsa # DMSA 

3075 self.key = key 

3076 self.subkey = None # In the AP-REQ authenticator 

3077 self.replykey = None # Key used for reply 

3078 # See RFC4120 - sect 7.2.2 

3079 # This marks whether we should follow-up after an EOF 

3080 self.should_followup = False 

3081 # This marks that we sent a FAST-req and are awaiting for an answer 

3082 self.fast_req_sent = False 

3083 # Session parameters 

3084 self.pre_auth = False 

3085 self.fast_rep = None 

3086 self.fast_error = None 

3087 self.fast_skey = None # The random subkey used for fast 

3088 self.fast_armorkey = None # The armor key 

3089 self.fxcookie = None 

3090 

3091 sock = self._connect() 

3092 super(KerberosClient, self).__init__( 

3093 sock=sock, 

3094 **kwargs, 

3095 ) 

3096 

3097 def _connect(self): 

3098 """ 

3099 Internal function to bind a socket to the DC. 

3100 This also takes care of an eventual KDC proxy. 

3101 """ 

3102 if self.kdc_proxy: 

3103 # If we are using a KDC Proxy, wrap the socket with the KdcProxySocket, 

3104 # that takes our messages and transport them over HTTP. 

3105 sock = KdcProxySocket( 

3106 url=self.kdc_proxy, 

3107 targetDomain=self.realm, 

3108 no_check_certificate=self.kdc_proxy_no_check_certificate, 

3109 ) 

3110 else: 

3111 sock = socket.socket() 

3112 sock.settimeout(self._timeout) 

3113 sock.connect((self._ip, self._port)) 

3114 sock = StreamSocket(sock, KerberosTCPHeader) 

3115 return sock 

3116 

3117 def send(self, pkt): 

3118 """ 

3119 Sends a wrapped Kerberos packet 

3120 """ 

3121 super(KerberosClient, self).send(KerberosTCPHeader() / pkt) 

3122 

3123 def _base_kdc_req(self, now_time): 

3124 """ 

3125 Return the KRB_KDC_REQ_BODY used in both AS-REQ and TGS-REQ 

3126 """ 

3127 kdcreq = KRB_KDC_REQ_BODY( 

3128 etype=[ASN1_INTEGER(x) for x in self.etypes], 

3129 additionalTickets=None, 

3130 # Windows default 

3131 kdcOptions="forwardable+renewable+canonicalize+renewable-ok", 

3132 cname=None, 

3133 realm=ASN1_GENERAL_STRING(self.realm), 

3134 till=ASN1_GENERALIZED_TIME(now_time + timedelta(hours=10)), 

3135 rtime=ASN1_GENERALIZED_TIME(now_time + timedelta(hours=10)), 

3136 nonce=ASN1_INTEGER(RandNum(0, 0x7FFFFFFF)._fix()), 

3137 ) 

3138 if self.renew: 

3139 kdcreq.kdcOptions.set(30, 1) # set 'renew' (bit 30) 

3140 return kdcreq 

3141 

3142 def calc_fast_armorkey(self): 

3143 """ 

3144 Calculate and return the FAST armorkey 

3145 """ 

3146 # Generate a random key of the same type than ticket_skey 

3147 from scapy.libs.rfc3961 import Key, KRB_FX_CF2 

3148 

3149 if self.mode == self.MODE.AS_REQ: 

3150 # AS-REQ mode 

3151 self.fast_skey = Key.new_random_key(self.armor_ticket_skey.etype) 

3152 

3153 self.fast_armorkey = KRB_FX_CF2( 

3154 self.fast_skey, 

3155 self.armor_ticket_skey, 

3156 b"subkeyarmor", 

3157 b"ticketarmor", 

3158 ) 

3159 elif self.mode == self.MODE.TGS_REQ: 

3160 # TGS-REQ: 2 cases 

3161 

3162 self.subkey = Key.new_random_key(self.key.etype) 

3163 

3164 if not self.armor_ticket: 

3165 # Case 1: Implicit armoring 

3166 self.fast_armorkey = KRB_FX_CF2( 

3167 self.subkey, 

3168 self.key, 

3169 b"subkeyarmor", 

3170 b"ticketarmor", 

3171 ) 

3172 else: 

3173 # Case 2: Explicit armoring, in "Compounded Identity mode". 

3174 # This is a Microsoft extension: see [MS-KILE] sect 3.3.5.7.4 

3175 

3176 self.fast_skey = Key.new_random_key(self.armor_ticket_skey.etype) 

3177 

3178 explicit_armor_key = KRB_FX_CF2( 

3179 self.fast_skey, 

3180 self.armor_ticket_skey, 

3181 b"subkeyarmor", 

3182 b"ticketarmor", 

3183 ) 

3184 

3185 self.fast_armorkey = KRB_FX_CF2( 

3186 explicit_armor_key, 

3187 self.subkey, 

3188 b"explicitarmor", 

3189 b"tgsarmor", 

3190 ) 

3191 

3192 def _fast_wrap(self, kdc_req, padata, now_time, pa_tgsreq_ap=None): 

3193 """ 

3194 :param kdc_req: the KDC_REQ_BODY to wrap 

3195 :param padata: the list of PADATA to wrap 

3196 :param now_time: the current timestamp used by the client 

3197 """ 

3198 

3199 # Create the PA Fast request wrapper 

3200 pafastreq = PA_FX_FAST_REQUEST( 

3201 armoredData=KrbFastArmoredReq( 

3202 reqChecksum=Checksum(), 

3203 encFastReq=EncryptedData(), 

3204 ) 

3205 ) 

3206 

3207 if self.armor_ticket is not None: 

3208 # EXPLICIT mode only (AS-REQ or TGS-REQ) 

3209 

3210 pafastreq.armoredData.armor = KrbFastArmor( 

3211 armorType=1, # FX_FAST_ARMOR_AP_REQUEST 

3212 armorValue=KRB_AP_REQ( 

3213 ticket=self.armor_ticket, 

3214 authenticator=EncryptedData(), 

3215 ), 

3216 ) 

3217 

3218 # Populate the authenticator. Note the client is the wrapper 

3219 _, crealm = _parse_upn(self.armor_ticket_upn) 

3220 authenticator = KRB_Authenticator( 

3221 crealm=ASN1_GENERAL_STRING(crealm), 

3222 cname=PrincipalName.fromUPN(self.armor_ticket_upn), 

3223 cksum=None, 

3224 ctime=ASN1_GENERALIZED_TIME(now_time), 

3225 cusec=ASN1_INTEGER(0), 

3226 subkey=EncryptionKey.fromKey(self.fast_skey), 

3227 seqNumber=ASN1_INTEGER(0), 

3228 encAuthorizationData=None, 

3229 ) 

3230 pafastreq.armoredData.armor.armorValue.authenticator.encrypt( 

3231 self.armor_ticket_skey, 

3232 authenticator, 

3233 ) 

3234 

3235 # Sign the fast request wrapper 

3236 if self.mode == self.MODE.TGS_REQ: 

3237 # "for a TGS-REQ, it is performed over the type AP- 

3238 # REQ in the PA-TGS-REQ padata of the TGS request" 

3239 pafastreq.armoredData.reqChecksum.make( 

3240 self.fast_armorkey, 

3241 bytes(pa_tgsreq_ap), 

3242 ) 

3243 else: 

3244 # "For an AS-REQ, it is performed over the type KDC-REQ- 

3245 # BODY for the req-body field of the KDC-REQ structure of the 

3246 # containing message" 

3247 pafastreq.armoredData.reqChecksum.make( 

3248 self.fast_armorkey, 

3249 bytes(kdc_req), 

3250 ) 

3251 

3252 # Build and encrypt the Fast request 

3253 fastreq = KrbFastReq( 

3254 padata=padata, 

3255 reqBody=kdc_req, 

3256 ) 

3257 pafastreq.armoredData.encFastReq.encrypt( 

3258 self.fast_armorkey, 

3259 fastreq, 

3260 ) 

3261 

3262 # Return the PADATA 

3263 return PADATA( 

3264 padataType=ASN1_INTEGER(136), # PA-FX-FAST 

3265 padataValue=pafastreq, 

3266 ) 

3267 

3268 def as_req(self): 

3269 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

3270 

3271 # 1. Build and populate KDC-REQ 

3272 kdc_req = self._base_kdc_req(now_time=now_time) 

3273 kdc_req.addresses = [ 

3274 HostAddress( 

3275 addrType=ASN1_INTEGER(20), # Netbios 

3276 address=ASN1_STRING(self.host.ljust(16, " ")), 

3277 ) 

3278 ] 

3279 kdc_req.cname = PrincipalName.fromUPN(self.upn) 

3280 kdc_req.sname = PrincipalName.fromSPN(self.spn) 

3281 

3282 # 2. Build the list of PADATA 

3283 padata = [ 

3284 PADATA( 

3285 padataType=ASN1_INTEGER(128), # PA-PAC-REQUEST 

3286 padataValue=PA_PAC_REQUEST(includePac=ASN1_BOOLEAN(-1)), 

3287 ) 

3288 ] 

3289 

3290 # Cookie support 

3291 if self.fxcookie: 

3292 padata.insert( 

3293 0, 

3294 PADATA( 

3295 padataType=133, # PA-FX-COOKIE 

3296 padataValue=self.fxcookie, 

3297 ), 

3298 ) 

3299 

3300 # FAST 

3301 if self.fast: 

3302 # Calculate the armor key 

3303 self.calc_fast_armorkey() 

3304 

3305 # [MS-KILE] sect 3.2.5.5 

3306 # "When sending the AS-REQ, add a PA-PAC-OPTIONS [167]" 

3307 padata.append( 

3308 PADATA( 

3309 padataType=ASN1_INTEGER(167), # PA-PAC-OPTIONS 

3310 padataValue=PA_PAC_OPTIONS( 

3311 options="Claims", 

3312 ), 

3313 ) 

3314 ) 

3315 

3316 # Pre-auth is requested 

3317 if self.pre_auth: 

3318 if self.x509: 

3319 # Special PKINIT (RFC4556) factor 

3320 pafactor = PADATA( 

3321 padataType=16, padataValue=PA_PK_AS_REQ() # PA-PK-AS-REQ 

3322 ) 

3323 raise NotImplementedError("PKINIT isn't implemented yet !") 

3324 else: 

3325 # Key-based factor 

3326 

3327 if self.fast: 

3328 # Special FAST factor 

3329 # RFC6113 sect 5.4.6 

3330 from scapy.libs.rfc3961 import KRB_FX_CF2 

3331 

3332 # Calculate the 'challenge key' 

3333 ts_key = KRB_FX_CF2( 

3334 self.fast_armorkey, 

3335 self.key, 

3336 b"clientchallengearmor", 

3337 b"challengelongterm", 

3338 ) 

3339 pafactor = PADATA( 

3340 padataType=138, # PA-ENCRYPTED-CHALLENGE 

3341 padataValue=EncryptedData(), 

3342 ) 

3343 else: 

3344 # Usual 'timestamp' factor 

3345 ts_key = self.key 

3346 pafactor = PADATA( 

3347 padataType=2, # PA-ENC-TIMESTAMP 

3348 padataValue=EncryptedData(), 

3349 ) 

3350 pafactor.padataValue.encrypt( 

3351 ts_key, 

3352 PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), 

3353 ) 

3354 

3355 # Insert Pre-Authentication data 

3356 padata.insert( 

3357 0, 

3358 pafactor, 

3359 ) 

3360 

3361 # FAST support 

3362 if self.fast: 

3363 # We are using RFC6113's FAST armoring. The PADATA's are therefore 

3364 # hidden inside the encrypted section. 

3365 padata = [ 

3366 self._fast_wrap( 

3367 kdc_req=kdc_req, 

3368 padata=padata, 

3369 now_time=now_time, 

3370 ) 

3371 ] 

3372 

3373 # 3. Build the request 

3374 asreq = Kerberos( 

3375 root=KRB_AS_REQ( 

3376 padata=padata, 

3377 reqBody=kdc_req, 

3378 ) 

3379 ) 

3380 

3381 # Note the reply key 

3382 self.replykey = self.key 

3383 

3384 return asreq 

3385 

3386 def tgs_req(self): 

3387 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

3388 

3389 # Compute armor key for FAST 

3390 if self.fast: 

3391 self.calc_fast_armorkey() 

3392 

3393 # 1. Build and populate KDC-REQ 

3394 kdc_req = self._base_kdc_req(now_time=now_time) 

3395 kdc_req.sname = PrincipalName.fromSPN(self.spn) 

3396 

3397 # Additional tickets 

3398 if self.additional_tickets: 

3399 kdc_req.additionalTickets = self.additional_tickets 

3400 

3401 # U2U 

3402 if self.u2u: 

3403 kdc_req.kdcOptions.set(28, 1) # set 'enc-tkt-in-skey' (bit 28) 

3404 

3405 # 2. Build the list of PADATA 

3406 padata = [] 

3407 

3408 # [MS-SFU] FOR-USER extension 

3409 if self.for_user is not None: 

3410 from scapy.libs.rfc3961 import ChecksumType, EncryptionType 

3411 

3412 # [MS-SFU] note 4: 

3413 # "Windows Vista, Windows Server 2008, Windows 7, and Windows Server 

3414 # 2008 R2 send the PA-S4U-X509-USER padata type alone if the user's 

3415 # certificate is available. 

3416 # If the user's certificate is not available, it sends both the 

3417 # PA-S4U-X509-USER padata type and the PA-FOR-USER padata type. 

3418 # When the PA-S4U-X509-USER padata type is used without the user's 

3419 # certificate, the certificate field is not present." 

3420 

3421 # 1. Add PA_S4U_X509_USER 

3422 pasfux509 = PA_S4U_X509_USER( 

3423 userId=S4UUserID( 

3424 nonce=kdc_req.nonce, 

3425 # [MS-SFU] note 5: 

3426 # "Windows S4U clients always set this option." 

3427 options="USE_REPLY_KEY_USAGE", 

3428 cname=PrincipalName.fromUPN(self.for_user), 

3429 crealm=ASN1_GENERAL_STRING(_parse_upn(self.for_user)[1]), 

3430 subjectCertificate=None, # TODO 

3431 ), 

3432 checksum=Checksum(), 

3433 ) 

3434 

3435 if self.dmsa: 

3436 # DMSA = set UNCONDITIONAL_DELEGATION to 1 

3437 pasfux509.userId.options.set(4, 1) 

3438 

3439 if self.key.etype in [EncryptionType.RC4_HMAC, EncryptionType.RC4_HMAC_EXP]: 

3440 # "if the key's encryption type is RC4_HMAC_NT (23) the checksum type 

3441 # is rsa-md4 (2) as defined in section 6.2.6 of [RFC3961]." 

3442 pasfux509.checksum.make( 

3443 self.key, 

3444 bytes(pasfux509.userId), 

3445 cksumtype=ChecksumType.RSA_MD4, 

3446 ) 

3447 else: 

3448 pasfux509.checksum.make( 

3449 self.key, 

3450 bytes(pasfux509.userId), 

3451 ) 

3452 padata.append( 

3453 PADATA( 

3454 padataType=ASN1_INTEGER(130), # PA-FOR-X509-USER 

3455 padataValue=pasfux509, 

3456 ) 

3457 ) 

3458 

3459 # 2. Add PA_FOR_USER 

3460 if True: # XXX user's certificate is not available. 

3461 paforuser = PA_FOR_USER( 

3462 userName=PrincipalName.fromUPN(self.for_user), 

3463 userRealm=ASN1_GENERAL_STRING(_parse_upn(self.for_user)[1]), 

3464 cksum=Checksum(), 

3465 ) 

3466 S4UByteArray = struct.pack( # [MS-SFU] sect 2.2.1 

3467 "<I", paforuser.userName.nameType.val 

3468 ) + ( 

3469 ( 

3470 "".join(x.val for x in paforuser.userName.nameString) 

3471 + paforuser.userRealm.val 

3472 + paforuser.authPackage.val 

3473 ).encode() 

3474 ) 

3475 paforuser.cksum.make( 

3476 self.key, 

3477 S4UByteArray, 

3478 cksumtype=ChecksumType.HMAC_MD5, 

3479 ) 

3480 padata.append( 

3481 PADATA( 

3482 padataType=ASN1_INTEGER(129), # PA-FOR-USER 

3483 padataValue=paforuser, 

3484 ) 

3485 ) 

3486 

3487 # [MS-SFU] S4U2proxy - sect 3.1.5.2.1 

3488 if self.s4u2proxy: 

3489 # "PA-PAC-OPTIONS with resource-based constrained-delegation bit set" 

3490 padata.append( 

3491 PADATA( 

3492 padataType=ASN1_INTEGER(167), # PA-PAC-OPTIONS 

3493 padataValue=PA_PAC_OPTIONS( 

3494 options="Resource-based-constrained-delegation", 

3495 ), 

3496 ) 

3497 ) 

3498 # "kdc-options field: MUST include the new cname-in-addl-tkt options flag" 

3499 kdc_req.kdcOptions.set(14, 1) 

3500 

3501 # [MS-KILE] 2.2.11 KERB-KEY-LIST-REQ 

3502 if self.key_list_req: 

3503 padata.append( 

3504 PADATA( 

3505 padataType=ASN1_INTEGER(161), # KERB-KEY-LIST-REQ 

3506 padataValue=KERB_KEY_LIST_REQ( 

3507 keytypes=[ASN1_INTEGER(x) for x in self.key_list_req] 

3508 ), 

3509 ) 

3510 ) 

3511 

3512 # 3. Build the AP-req inside a PA 

3513 apreq = KRB_AP_REQ(ticket=self.ticket, authenticator=EncryptedData()) 

3514 pa_tgs_req = PADATA( 

3515 padataType=ASN1_INTEGER(1), # PA-TGS-REQ 

3516 padataValue=apreq, 

3517 ) 

3518 

3519 # 4. Populate it's authenticator 

3520 _, crealm = _parse_upn(self.upn) 

3521 authenticator = KRB_Authenticator( 

3522 crealm=ASN1_GENERAL_STRING(crealm), 

3523 cname=PrincipalName.fromUPN(self.upn), 

3524 cksum=None, 

3525 ctime=ASN1_GENERALIZED_TIME(now_time), 

3526 cusec=ASN1_INTEGER(0), 

3527 subkey=EncryptionKey.fromKey(self.subkey) if self.subkey else None, 

3528 seqNumber=None, 

3529 encAuthorizationData=None, 

3530 ) 

3531 

3532 # Compute checksum 

3533 if self.key.cksumtype: 

3534 authenticator.cksum = Checksum() 

3535 authenticator.cksum.make( 

3536 self.key, 

3537 bytes(kdc_req), 

3538 ) 

3539 

3540 # Encrypt authenticator 

3541 apreq.authenticator.encrypt(self.key, authenticator) 

3542 

3543 # 5. Process FAST if required 

3544 if self.fast: 

3545 padata = [ 

3546 self._fast_wrap( 

3547 kdc_req=kdc_req, 

3548 padata=padata, 

3549 now_time=now_time, 

3550 pa_tgsreq_ap=apreq, 

3551 ) 

3552 ] 

3553 

3554 # 6. Add the final PADATA 

3555 padata.append(pa_tgs_req) 

3556 

3557 # 7. Build the request 

3558 tgsreq = Kerberos( 

3559 root=KRB_TGS_REQ( 

3560 padata=padata, 

3561 reqBody=kdc_req, 

3562 ) 

3563 ) 

3564 

3565 # Note the reply key 

3566 if self.subkey: 

3567 self.replykey = self.subkey 

3568 else: 

3569 self.replykey = self.key 

3570 

3571 return tgsreq 

3572 

3573 @ATMT.state(initial=1) 

3574 def BEGIN(self): 

3575 pass 

3576 

3577 @ATMT.condition(BEGIN) 

3578 def should_send_as_req(self): 

3579 if self.mode in [self.MODE.AS_REQ, self.MODE.GET_SALT]: 

3580 raise self.SENT_AS_REQ() 

3581 

3582 @ATMT.condition(BEGIN) 

3583 def should_send_tgs_req(self): 

3584 if self.mode == self.MODE.TGS_REQ: 

3585 raise self.SENT_TGS_REQ() 

3586 

3587 @ATMT.action(should_send_as_req) 

3588 def send_as_req(self): 

3589 self.send(self.as_req()) 

3590 

3591 @ATMT.action(should_send_tgs_req) 

3592 def send_tgs_req(self): 

3593 self.send(self.tgs_req()) 

3594 

3595 @ATMT.state() 

3596 def SENT_AS_REQ(self): 

3597 pass 

3598 

3599 @ATMT.state() 

3600 def SENT_TGS_REQ(self): 

3601 pass 

3602 

3603 def _process_padatas_and_key(self, padatas): 

3604 from scapy.libs.rfc3961 import EncryptionType, Key, KRB_FX_CF2 

3605 

3606 etype = None 

3607 salt = b"" 

3608 # 1. Process pa-data 

3609 if padatas is not None: 

3610 for padata in padatas: 

3611 if padata.padataType == 0x13 and etype is None: # PA-ETYPE-INFO2 

3612 elt = padata.padataValue.seq[0] 

3613 if elt.etype.val in self.etypes: 

3614 etype = elt.etype.val 

3615 if etype != EncryptionType.RC4_HMAC: 

3616 salt = elt.salt.val 

3617 elif padata.padataType == 133: # PA-FX-COOKIE 

3618 self.fxcookie = padata.padataValue 

3619 elif padata.padataType == 136: # PA-FX-FAST 

3620 if isinstance(padata.padataValue, PA_FX_FAST_REPLY): 

3621 self.fast_rep = ( 

3622 padata.padataValue.armoredData.encFastRep.decrypt( 

3623 self.fast_armorkey, 

3624 ) 

3625 ) 

3626 elif padata.padataType == 137: # PA-FX-ERROR 

3627 self.fast_error = padata.padataValue 

3628 elif padata.padataType == 130: # PA-FOR-X509-USER 

3629 # Verify S4U checksum 

3630 key_usage_number = None 

3631 pasfux509 = padata.padataValue 

3632 # [MS-SFU] sect 2.2.2 

3633 # "In a reply, indicates that it was signed with key usage 27" 

3634 if pasfux509.userId.options.val[2] == "1": # USE_REPLY_KEY_USAGE 

3635 key_usage_number = 27 

3636 pasfux509.checksum.verify( 

3637 self.key, 

3638 bytes(pasfux509.userId), 

3639 key_usage_number=key_usage_number, 

3640 ) 

3641 

3642 # 2. Update the current key if necessary 

3643 

3644 # Compute key if not already provided 

3645 if self.key is None and etype is not None: 

3646 self.key = Key.string_to_key( 

3647 etype, 

3648 self.password, 

3649 salt, 

3650 ) 

3651 

3652 # Update the key with the fast reply, if necessary 

3653 if self.fast_rep and self.fast_rep.strengthenKey: 

3654 # "The strengthen-key field MAY be set in an AS reply" 

3655 self.replykey = KRB_FX_CF2( 

3656 self.fast_rep.strengthenKey.toKey(), 

3657 self.replykey, 

3658 b"strengthenkey", 

3659 b"replykey", 

3660 ) 

3661 

3662 @ATMT.receive_condition(SENT_AS_REQ, prio=0) 

3663 def receive_salt_mode(self, pkt): 

3664 # This is only for "Salt-Mode", a mode where we get the salt then 

3665 # exit. 

3666 if self.mode == self.MODE.GET_SALT: 

3667 if Kerberos not in pkt: 

3668 raise self.FINAL() 

3669 if not isinstance(pkt.root, KRB_ERROR): 

3670 log_runtime.error("Pre-auth is likely disabled !") 

3671 raise self.FINAL() 

3672 if pkt.root.errorCode == 25: # KDC_ERR_PREAUTH_REQUIRED 

3673 for padata in pkt.root.eData.seq: 

3674 if padata.padataType == 0x13: # PA-ETYPE-INFO2 

3675 elt = padata.padataValue.seq[0] 

3676 if elt.etype.val in self.etypes: 

3677 self.result = elt.salt.val 

3678 raise self.FINAL() 

3679 else: 

3680 log_runtime.error("Failed to retrieve the salt !") 

3681 raise self.FINAL() 

3682 

3683 @ATMT.receive_condition(SENT_AS_REQ, prio=1) 

3684 def receive_krb_error_as_req(self, pkt): 

3685 # We check for Kerberos errors. 

3686 # There is a special case for PREAUTH_REQUIRED error, which means that preauth 

3687 # is required and we need to do a second exchange. 

3688 if Kerberos in pkt and isinstance(pkt.root, KRB_ERROR): 

3689 # Process PAs if available 

3690 if pkt.root.eData and isinstance(pkt.root.eData, MethodData): 

3691 self._process_padatas_and_key(pkt.root.eData.seq) 

3692 

3693 # Special case for FAST errors 

3694 if self.fast_rep: 

3695 # This is actually a fast response error ! 

3696 frep, self.fast_rep = self.fast_rep, None 

3697 # Re-process PAs 

3698 self._process_padatas_and_key(frep.padata) 

3699 # Extract real Kerberos error from FAST message 

3700 ferr = Kerberos(root=self.fast_error) 

3701 self.fast_error = None 

3702 # Recurse 

3703 self.receive_krb_error_as_req(ferr) 

3704 return 

3705 

3706 if pkt.root.errorCode == 25: # KDC_ERR_PREAUTH_REQUIRED 

3707 if not self.key: 

3708 log_runtime.error( 

3709 "Got 'KDC_ERR_PREAUTH_REQUIRED', " 

3710 "but no possible key could be computed." 

3711 ) 

3712 raise self.FINAL() 

3713 self.should_followup = True 

3714 self.pre_auth = True 

3715 raise self.BEGIN() 

3716 else: 

3717 log_runtime.error("Received KRB_ERROR") 

3718 pkt.show() 

3719 raise self.FINAL() 

3720 

3721 @ATMT.receive_condition(SENT_AS_REQ, prio=2) 

3722 def receive_as_rep(self, pkt): 

3723 if Kerberos in pkt and isinstance(pkt.root, KRB_AS_REP): 

3724 raise self.FINAL().action_parameters(pkt) 

3725 

3726 @ATMT.eof(SENT_AS_REQ) 

3727 def retry_after_eof_in_apreq(self): 

3728 if self.should_followup: 

3729 # Reconnect and Restart 

3730 self.should_followup = False 

3731 self.update_sock(self._connect()) 

3732 raise self.BEGIN() 

3733 else: 

3734 log_runtime.error("Socket was closed in an unexpected state") 

3735 raise self.FINAL() 

3736 

3737 @ATMT.action(receive_as_rep) 

3738 def decrypt_as_rep(self, pkt): 

3739 self._process_padatas_and_key(pkt.root.padata) 

3740 if not self.pre_auth: 

3741 log_runtime.warning("Pre-authentication was disabled for this account !") 

3742 

3743 # Process FAST response 

3744 if self.fast_rep: 

3745 # Verify the ticket-checksum 

3746 self.fast_rep.finished.ticketChecksum.verify( 

3747 self.fast_armorkey, 

3748 bytes(pkt.root.ticket), 

3749 ) 

3750 self.fast_rep = None 

3751 elif self.fast: 

3752 raise ValueError("Answer was not FAST ! Is it supported?") 

3753 

3754 # Decrypt AS-REP response 

3755 enc = pkt.root.encPart 

3756 res = enc.decrypt(self.replykey) 

3757 self.result = self.RES_AS_MODE(pkt.root, res.key.toKey(), res) 

3758 

3759 @ATMT.receive_condition(SENT_TGS_REQ) 

3760 def receive_krb_error_tgs_req(self, pkt): 

3761 if Kerberos in pkt and isinstance(pkt.root, KRB_ERROR): 

3762 # Process PAs if available 

3763 if pkt.root.eData and isinstance(pkt.root.eData, MethodData): 

3764 self._process_padatas_and_key(pkt.root.eData.seq) 

3765 

3766 if self.fast_rep: 

3767 # This is actually a fast response error ! 

3768 frep, self.fast_rep = self.fast_rep, None 

3769 # Re-process PAs 

3770 self._process_padatas_and_key(frep.padata) 

3771 # Extract real Kerberos error from FAST message 

3772 ferr = Kerberos(root=self.fast_error) 

3773 self.fast_error = None 

3774 # Recurse 

3775 self.receive_krb_error_tgs_req(ferr) 

3776 return 

3777 

3778 if ( 

3779 pkt.root.errorCode == 0x07 

3780 and isinstance(pkt.root.eData, KERB_ERROR_UNK) 

3781 and pkt.root.eData.dataType == -128 

3782 ): 

3783 log_runtime.warning( 

3784 "KDC requires U2U for SPN '%s' !" % pkt.root.getSPN() 

3785 ) 

3786 else: 

3787 log_runtime.warning("Received KRB_ERROR") 

3788 pkt.show() 

3789 raise self.FINAL() 

3790 

3791 @ATMT.receive_condition(SENT_TGS_REQ) 

3792 def receive_tgs_rep(self, pkt): 

3793 if Kerberos in pkt and isinstance(pkt.root, KRB_TGS_REP): 

3794 if ( 

3795 not self.renew 

3796 and not self.dmsa 

3797 and pkt.root.ticket.sname.nameString[0].val == b"krbtgt" 

3798 ): 

3799 log_runtime.warning("Received a cross-realm referral ticket !") 

3800 raise self.FINAL().action_parameters(pkt) 

3801 

3802 @ATMT.action(receive_tgs_rep) 

3803 def decrypt_tgs_rep(self, pkt): 

3804 self._process_padatas_and_key(pkt.root.padata) 

3805 

3806 # Process FAST response 

3807 if self.fast_rep: 

3808 # Verify the ticket-checksum 

3809 self.fast_rep.finished.ticketChecksum.verify( 

3810 self.fast_armorkey, 

3811 bytes(pkt.root.ticket), 

3812 ) 

3813 self.fast_rep = None 

3814 elif self.fast: 

3815 raise ValueError("Answer was not FAST ! Is it supported?") 

3816 

3817 # Decrypt TGS-REP response 

3818 enc = pkt.root.encPart 

3819 if self.subkey: 

3820 # "In a TGS-REP message, the key 

3821 # usage value is 8 if the TGS session key is used, or 9 if a TGS 

3822 # authenticator subkey is used." 

3823 res = enc.decrypt(self.replykey, key_usage_number=9, cls=EncTGSRepPart) 

3824 else: 

3825 res = enc.decrypt(self.replykey) 

3826 

3827 # Store result 

3828 self.result = self.RES_TGS_MODE(pkt.root, res.key.toKey(), res) 

3829 

3830 @ATMT.state(final=1) 

3831 def FINAL(self): 

3832 pass 

3833 

3834 

3835def _parse_upn(upn): 

3836 """ 

3837 Extract the username and realm from full UPN 

3838 """ 

3839 m = re.match(r"^([^@\\/]+)(@|\\)([^@\\/]+)$", upn) 

3840 if not m: 

3841 err = "Invalid UPN: '%s'" % upn 

3842 if "/" in upn: 

3843 err += ". Did you mean '%s' ?" % upn.replace("/", "\\") 

3844 elif "@" not in upn and "\\" not in upn: 

3845 err += ". Provide domain as so: '%s@domain.local'" % upn 

3846 raise ValueError(err) 

3847 if m.group(2) == "@": 

3848 user = m.group(1) 

3849 domain = m.group(3) 

3850 else: 

3851 user = m.group(3) 

3852 domain = m.group(1) 

3853 return user, domain 

3854 

3855 

3856def _parse_spn(spn): 

3857 """ 

3858 Extract ServiceName and realm from full SPN 

3859 """ 

3860 # See [MS-ADTS] sect 2.2.21 for SPN format. We discard the servicename. 

3861 m = re.match(r"^((?:[^@\\/]+)/(?:[^@\\/]+))(?:/[^@\\/]+)?(?:@([^@\\/]+))?$", spn) 

3862 if not m: 

3863 try: 

3864 # If SPN is a UPN, we are doing U2U :D 

3865 return _parse_upn(spn) 

3866 except ValueError: 

3867 raise ValueError("Invalid SPN: '%s'" % spn) 

3868 return m.group(1), m.group(2) 

3869 

3870 

3871def _spn_are_equal(spn1, spn2): 

3872 """ 

3873 Check that two SPNs are equal. 

3874 """ 

3875 spn1, _ = _parse_spn(spn1) 

3876 spn2, _ = _parse_spn(spn2) 

3877 return spn1.lower() == spn2.lower() 

3878 

3879 

3880def krb_as_req( 

3881 upn, 

3882 spn=None, 

3883 ip=None, 

3884 key=None, 

3885 password=None, 

3886 realm=None, 

3887 host="WIN10", 

3888 p12=None, 

3889 x509=None, 

3890 x509key=None, 

3891 **kwargs, 

3892): 

3893 r""" 

3894 Kerberos AS-Req 

3895 

3896 :param upn: the user principal name formatted as "DOMAIN\user", "DOMAIN/user" 

3897 or "user@DOMAIN" 

3898 :param spn: (optional) the full service principal name. 

3899 Defaults to "krbtgt/<realm>" 

3900 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for 

3901 _kerberos._tcp.dc._msdcs.domain.local). 

3902 :param key: (optional) pass the Key object. 

3903 :param password: (optional) otherwise, pass the user's password 

3904 :param x509: (optional) pass a x509 certificate for PKINIT. 

3905 :param x509key: (optional) pass the key of the x509 certificate for PKINIT. 

3906 :param p12: (optional) use a pfx/p12 instead of x509 and x509key. In this case, 

3907 'password' is the password of the p12. 

3908 :param realm: (optional) the realm to use. Otherwise use the one from UPN. 

3909 :param host: (optional) the host performing the AS-Req. WIN10 by default. 

3910 

3911 :return: returns a named tuple (asrep=<...>, sessionkey=<...>) 

3912 

3913 Example:: 

3914 

3915 >>> # The KDC is found via DC Locator, we ask a TGT for user1 

3916 >>> krb_as_req("user1@DOMAIN.LOCAL", password="Password1") 

3917 

3918 Equivalent:: 

3919 

3920 >>> from scapy.libs.rfc3961 import Key, EncryptionType 

3921 >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546 

3922 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

3923 >>> krb_as_req("user1@DOMAIN.LOCAL", ip="192.168.122.17", key=key) 

3924 

3925 Example using PKINIT with a p12:: 

3926 

3927 >>> krb_as_req("user1@DOMAIN.LOCAL", p12="./store.p12", password="password") 

3928 """ 

3929 if realm is None: 

3930 _, realm = _parse_upn(upn) 

3931 if key is None and p12 is None and x509 is None: 

3932 if password is None: 

3933 try: 

3934 from prompt_toolkit import prompt 

3935 

3936 password = prompt("Enter password: ", is_password=True) 

3937 except ImportError: 

3938 password = input("Enter password: ") 

3939 cli = KerberosClient( 

3940 mode=KerberosClient.MODE.AS_REQ, 

3941 realm=realm, 

3942 ip=ip, 

3943 spn=spn or "krbtgt/" + realm, 

3944 host=host, 

3945 upn=upn, 

3946 password=password, 

3947 key=key, 

3948 p12=p12, 

3949 x509=x509, 

3950 x509key=x509key, 

3951 **kwargs, 

3952 ) 

3953 cli.run() 

3954 cli.stop() 

3955 return cli.result 

3956 

3957 

3958def krb_tgs_req( 

3959 upn, 

3960 spn, 

3961 sessionkey, 

3962 ticket, 

3963 ip=None, 

3964 renew=False, 

3965 realm=None, 

3966 additional_tickets=[], 

3967 u2u=False, 

3968 etypes=None, 

3969 for_user=None, 

3970 s4u2proxy=False, 

3971 **kwargs, 

3972): 

3973 r""" 

3974 Kerberos TGS-Req 

3975 

3976 :param upn: the user principal name formatted as "DOMAIN\user", "DOMAIN/user" 

3977 or "user@DOMAIN" 

3978 :param spn: the full service principal name (e.g. "cifs/srv1") 

3979 :param sessionkey: the session key retrieved from the tgt 

3980 :param ticket: the tgt ticket 

3981 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for 

3982 _kerberos._tcp.dc._msdcs.domain.local). 

3983 :param renew: ask for renewal 

3984 :param realm: (optional) the realm to use. Otherwise use the one from SPN. 

3985 :param additional_tickets: (optional) a list of additional tickets to pass. 

3986 :param u2u: (optional) if specified, enable U2U and request the ticket to be 

3987 signed using the session key from the first additional ticket. 

3988 :param etypes: array of EncryptionType values. 

3989 By default: AES128, AES256, RC4, DES_MD5 

3990 :param for_user: a user principal name to request the ticket for. This is the 

3991 S4U2Self extension. 

3992 

3993 :return: returns a named tuple (tgsrep=<...>, sessionkey=<...>) 

3994 

3995 Example:: 

3996 

3997 >>> # The KDC is on 192.168.122.17, we ask a TGT for user1 

3998 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", password="Password1") 

3999 

4000 Equivalent:: 

4001 

4002 >>> from scapy.libs.rfc3961 import Key, EncryptionType 

4003 >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546 

4004 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

4005 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", key=key) 

4006 """ 

4007 cli = KerberosClient( 

4008 mode=KerberosClient.MODE.TGS_REQ, 

4009 realm=realm, 

4010 upn=upn, 

4011 ip=ip, 

4012 spn=spn, 

4013 key=sessionkey, 

4014 ticket=ticket, 

4015 renew=renew, 

4016 additional_tickets=additional_tickets, 

4017 u2u=u2u, 

4018 etypes=etypes, 

4019 for_user=for_user, 

4020 s4u2proxy=s4u2proxy, 

4021 **kwargs, 

4022 ) 

4023 cli.run() 

4024 cli.stop() 

4025 return cli.result 

4026 

4027 

4028def krb_as_and_tgs(upn, spn, ip=None, key=None, password=None, **kwargs): 

4029 """ 

4030 Kerberos AS-Req then TGS-Req 

4031 """ 

4032 res = krb_as_req(upn=upn, ip=ip, key=key, password=password, **kwargs) 

4033 if not res: 

4034 return 

4035 return krb_tgs_req( 

4036 upn=upn, 

4037 spn=spn, 

4038 sessionkey=res.sessionkey, 

4039 ticket=res.asrep.ticket, 

4040 ip=ip, 

4041 **kwargs, 

4042 ) 

4043 

4044 

4045def krb_get_salt(upn, ip=None, realm=None, host="WIN10", **kwargs): 

4046 """ 

4047 Kerberos AS-Req only to get the salt associated with the UPN. 

4048 """ 

4049 if realm is None: 

4050 _, realm = _parse_upn(upn) 

4051 cli = KerberosClient( 

4052 mode=KerberosClient.MODE.GET_SALT, 

4053 realm=realm, 

4054 ip=ip, 

4055 spn="krbtgt/" + realm, 

4056 upn=upn, 

4057 host=host, 

4058 **kwargs, 

4059 ) 

4060 cli.run() 

4061 cli.stop() 

4062 return cli.result 

4063 

4064 

4065def kpasswd( 

4066 upn, 

4067 targetupn=None, 

4068 ip=None, 

4069 password=None, 

4070 newpassword=None, 

4071 key=None, 

4072 ticket=None, 

4073 realm=None, 

4074 ssp=None, 

4075 setpassword=None, 

4076 timeout=3, 

4077 port=464, 

4078 debug=0, 

4079 **kwargs, 

4080): 

4081 """ 

4082 Change a password using RFC3244's Kerberos Set / Change Password. 

4083 

4084 :param upn: the UPN to use for authentication 

4085 :param targetupn: (optional) the UPN to change the password of. If not specified, 

4086 same as upn. 

4087 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for 

4088 _kerberos._tcp.dc._msdcs.domain.local). 

4089 :param key: (optional) pass the Key object. 

4090 :param ticket: (optional) a ticket to use. Either a TGT or ST for kadmin/changepw. 

4091 :param password: (optional) otherwise, pass the user's password 

4092 :param realm: (optional) the realm to use. Otherwise use the one from UPN. 

4093 :param setpassword: (optional) use "Set Password" mechanism. 

4094 :param ssp: (optional) a Kerberos SSP for the service kadmin/changepw@REALM. 

4095 If provided, you probably don't need anything else. Otherwise built. 

4096 """ 

4097 from scapy.layers.ldap import dclocator 

4098 

4099 if not realm: 

4100 _, realm = _parse_upn(upn) 

4101 spn = "kadmin/changepw@%s" % realm 

4102 if ip is None: 

4103 ip = dclocator( 

4104 realm, 

4105 timeout=timeout, 

4106 # Use connect mode instead of ldap for compatibility 

4107 # with MIT kerberos servers 

4108 mode="connect", 

4109 port=port, 

4110 debug=debug, 

4111 ).ip 

4112 if ssp is None and ticket is not None: 

4113 tktspn = ticket.getSPN().split("/")[0] 

4114 assert tktspn in ["krbtgt", "kadmin"], "Unexpected ticket type ! %s" % tktspn 

4115 if tktspn == "krbtgt": 

4116 log_runtime.info( 

4117 "Using 'Set Password' mode. This only works with admin privileges." 

4118 ) 

4119 setpassword = True 

4120 resp = krb_tgs_req( 

4121 upn=upn, 

4122 spn=spn, 

4123 ticket=ticket, 

4124 sessionkey=key, 

4125 ip=ip, 

4126 debug=debug, 

4127 ) 

4128 if resp is None: 

4129 return 

4130 ticket = resp.tgsrep.ticket 

4131 key = resp.sessionkey 

4132 if setpassword is None: 

4133 setpassword = bool(targetupn) 

4134 elif setpassword and targetupn is None: 

4135 targetupn = upn 

4136 assert setpassword or not targetupn, "Cannot use targetupn in changepassword mode !" 

4137 # Get a ticket for kadmin/changepw 

4138 if ssp is None: 

4139 if ticket is None: 

4140 # Get a ticket for kadmin/changepw through AS-REQ 

4141 resp = krb_as_req( 

4142 upn=upn, 

4143 spn=spn, 

4144 key=key, 

4145 ip=ip, 

4146 password=password, 

4147 debug=debug, 

4148 ) 

4149 if resp is None: 

4150 return 

4151 ticket = resp.asrep.ticket 

4152 key = resp.sessionkey 

4153 ssp = KerberosSSP( 

4154 UPN=upn, 

4155 SPN=spn, 

4156 ST=ticket, 

4157 KEY=key, 

4158 DC_IP=ip, 

4159 debug=debug, 

4160 **kwargs, 

4161 ) 

4162 Context, tok, negResult = ssp.GSS_Init_sec_context( 

4163 None, 

4164 req_flags=0, # No GSS_C_MUTUAL_FLAG 

4165 ) 

4166 if negResult != GSS_S_CONTINUE_NEEDED: 

4167 warning("SSP failed on initial GSS_Init_sec_context !") 

4168 if tok: 

4169 tok.show() 

4170 return 

4171 apreq = tok.innerToken.root 

4172 # Connect 

4173 sock = socket.socket() 

4174 sock.settimeout(timeout) 

4175 sock.connect((ip, port)) 

4176 sock = StreamSocket(sock, KpasswdTCPHeader) 

4177 # Do KPASSWD request 

4178 if newpassword is None: 

4179 try: 

4180 from prompt_toolkit import prompt 

4181 

4182 newpassword = prompt("Enter NEW password: ", is_password=True) 

4183 except ImportError: 

4184 newpassword = input("Enter NEW password: ") 

4185 krbpriv = KRB_PRIV(encPart=EncryptedData()) 

4186 krbpriv.encPart.encrypt( 

4187 Context.KrbSessionKey, 

4188 EncKrbPrivPart( 

4189 sAddress=HostAddress( 

4190 addrType=ASN1_INTEGER(2), # IPv4 

4191 address=ASN1_STRING(b"\xc0\xa8\x00e"), 

4192 ), 

4193 userData=ASN1_STRING( 

4194 bytes( 

4195 ChangePasswdData( 

4196 newpasswd=newpassword, 

4197 targname=PrincipalName.fromUPN(targetupn), 

4198 targrealm=realm, 

4199 ) 

4200 ) 

4201 if setpassword 

4202 else newpassword 

4203 ), 

4204 timestamp=None, 

4205 usec=None, 

4206 seqNumber=Context.SendSeqNum, 

4207 ), 

4208 ) 

4209 resp = sock.sr1( 

4210 KpasswdTCPHeader() 

4211 / KPASSWD_REQ( 

4212 pvno=0xFF80 if setpassword else 1, 

4213 apreq=apreq, 

4214 krbpriv=krbpriv, 

4215 ), 

4216 timeout=timeout, 

4217 verbose=0, 

4218 ) 

4219 # Verify KPASSWD response 

4220 if not resp: 

4221 raise TimeoutError("KPASSWD_REQ timed out !") 

4222 if KPASSWD_REP not in resp: 

4223 resp.show() 

4224 raise ValueError("Invalid response to KPASSWD_REQ !") 

4225 Context, tok, negResult = ssp.GSS_Init_sec_context(Context, resp.aprep) 

4226 if negResult != GSS_S_COMPLETE: 

4227 warning("SSP failed on subsequent GSS_Init_sec_context !") 

4228 if tok: 

4229 tok.show() 

4230 return 

4231 # Parse answer KRB_PRIV 

4232 krbanswer = resp.krbpriv.encPart.decrypt(Context.KrbSessionKey) 

4233 userRep = KPasswdRepData(krbanswer.userData.val) 

4234 if userRep.resultCode != 0: 

4235 warning(userRep.sprintf("KPASSWD failed !")) 

4236 userRep.show() 

4237 return 

4238 print(userRep.sprintf("%resultCode%")) 

4239 

4240 

4241# SSP 

4242 

4243 

4244class KerberosSSP(SSP): 

4245 """ 

4246 The KerberosSSP 

4247 

4248 Client settings: 

4249 

4250 :param ST: the service ticket to use for access. 

4251 If not provided, will be retrieved 

4252 :param SPN: the SPN of the service to use. If not provided, will use the 

4253 target_name provided in the GSS_Init_sec_context 

4254 :param UPN: The client UPN 

4255 :param DC_IP: (optional) is ST+KEY are not provided, will need to contact 

4256 the KDC at this IP. If not provided, will perform dc locator. 

4257 :param TGT: (optional) pass a TGT to use to get the ST. 

4258 :param KEY: the session key associated with the ST if it is provided, 

4259 OR the session key associated with the TGT 

4260 OR the kerberos key associated with the UPN 

4261 :param PASSWORD: (optional) if a UPN is provided and not a KEY, this is the 

4262 password of the UPN. 

4263 :param U2U: (optional) use U2U when requesting the ST. 

4264 

4265 Server settings: 

4266 

4267 :param SPN: the SPN of the service to use. 

4268 :param KEY: the kerberos key to use to decrypt the AP-req 

4269 :param UPN: (optional) the UPN, if used in U2U mode. 

4270 :param TGT: (optional) pass a TGT to use for U2U. 

4271 :param DC_IP: (optional) if TGT is not provided, request one on the KDC at 

4272 this IP using using the KEY when using U2U. 

4273 """ 

4274 

4275 oid = "1.2.840.113554.1.2.2" 

4276 auth_type = 0x10 

4277 

4278 class STATE(SSP.STATE): 

4279 INIT = 1 

4280 CLI_SENT_TGTREQ = 2 

4281 CLI_SENT_APREQ = 3 

4282 CLI_RCVD_APREP = 4 

4283 SRV_SENT_APREP = 5 

4284 FAILED = -1 

4285 

4286 class CONTEXT(SSP.CONTEXT): 

4287 __slots__ = [ 

4288 "SessionKey", 

4289 "ServerHostname", 

4290 "U2U", 

4291 "KrbSessionKey", # raw Key object 

4292 "STSessionKey", # raw ST Key object (for DCE_STYLE) 

4293 "SeqNum", # for AP 

4294 "SendSeqNum", # for MIC 

4295 "RecvSeqNum", # for MIC 

4296 "IsAcceptor", 

4297 "SendSealKeyUsage", 

4298 "SendSignKeyUsage", 

4299 "RecvSealKeyUsage", 

4300 "RecvSignKeyUsage", 

4301 # server-only 

4302 "UPN", 

4303 "PAC", 

4304 ] 

4305 

4306 def __init__(self, IsAcceptor, req_flags=None): 

4307 self.state = KerberosSSP.STATE.INIT 

4308 self.SessionKey = None 

4309 self.ServerHostname = None 

4310 self.U2U = False 

4311 self.SendSeqNum = 0 

4312 self.RecvSeqNum = 0 

4313 self.KrbSessionKey = None 

4314 self.STSessionKey = None 

4315 self.IsAcceptor = IsAcceptor 

4316 self.UPN = None 

4317 self.PAC = None 

4318 # [RFC 4121] sect 2 

4319 if IsAcceptor: 

4320 self.SendSealKeyUsage = 22 

4321 self.SendSignKeyUsage = 23 

4322 self.RecvSealKeyUsage = 24 

4323 self.RecvSignKeyUsage = 25 

4324 else: 

4325 self.SendSealKeyUsage = 24 

4326 self.SendSignKeyUsage = 25 

4327 self.RecvSealKeyUsage = 22 

4328 self.RecvSignKeyUsage = 23 

4329 super(KerberosSSP.CONTEXT, self).__init__(req_flags=req_flags) 

4330 

4331 def clifailure(self): 

4332 self.__init__(self.IsAcceptor, req_flags=self.flags) 

4333 

4334 def __repr__(self): 

4335 if self.U2U: 

4336 return "KerberosSSP-U2U" 

4337 return "KerberosSSP" 

4338 

4339 def __init__( 

4340 self, 

4341 ST=None, 

4342 UPN=None, 

4343 PASSWORD=None, 

4344 U2U=False, 

4345 KEY=None, 

4346 SPN=None, 

4347 TGT=None, 

4348 DC_IP=None, 

4349 SKEY_TYPE=None, 

4350 debug=0, 

4351 **kwargs, 

4352 ): 

4353 self.ST = ST 

4354 self.UPN = UPN 

4355 self.KEY = KEY 

4356 self.SPN = SPN 

4357 self.TGT = TGT 

4358 self.PASSWORD = PASSWORD 

4359 self.U2U = U2U 

4360 self.DC_IP = DC_IP 

4361 self.debug = debug 

4362 if SKEY_TYPE is None: 

4363 from scapy.libs.rfc3961 import EncryptionType 

4364 

4365 SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96 

4366 self.SKEY_TYPE = SKEY_TYPE 

4367 super(KerberosSSP, self).__init__(**kwargs) 

4368 

4369 def GSS_GetMICEx(self, Context, msgs, qop_req=0): 

4370 """ 

4371 [MS-KILE] sect 3.4.5.6 

4372 

4373 - AES: RFC4121 sect 4.2.6.1 

4374 """ 

4375 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4376 # Concatenate the ToSign 

4377 ToSign = b"".join(x.data for x in msgs if x.sign) 

4378 sig = KRB_InnerToken( 

4379 TOK_ID=b"\x04\x04", 

4380 root=KRB_GSS_MIC( 

4381 Flags="AcceptorSubkey" 

4382 + ("+SentByAcceptor" if Context.IsAcceptor else ""), 

4383 SND_SEQ=Context.SendSeqNum, 

4384 ), 

4385 ) 

4386 ToSign += bytes(sig)[:16] 

4387 sig.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

4388 keyusage=Context.SendSignKeyUsage, 

4389 text=ToSign, 

4390 ) 

4391 else: 

4392 raise NotImplementedError 

4393 Context.SendSeqNum += 1 

4394 return sig 

4395 

4396 def GSS_VerifyMICEx(self, Context, msgs, signature): 

4397 """ 

4398 [MS-KILE] sect 3.4.5.7 

4399 

4400 - AES: RFC4121 sect 4.2.6.1 

4401 """ 

4402 Context.RecvSeqNum = signature.root.SND_SEQ 

4403 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4404 # Concatenate the ToSign 

4405 ToSign = b"".join(x.data for x in msgs if x.sign) 

4406 ToSign += bytes(signature)[:16] 

4407 sig = Context.KrbSessionKey.make_checksum( 

4408 keyusage=Context.RecvSignKeyUsage, 

4409 text=ToSign, 

4410 ) 

4411 else: 

4412 raise NotImplementedError 

4413 if sig != signature.root.SGN_CKSUM: 

4414 raise ValueError("ERROR: Checksums don't match") 

4415 

4416 def GSS_WrapEx(self, Context, msgs, qop_req=0): 

4417 """ 

4418 [MS-KILE] sect 3.4.5.4 

4419 

4420 - AES: RFC4121 sect 4.2.6.2 and [MS-KILE] sect 3.4.5.4.1 

4421 - HMAC-RC4: RFC4757 sect 7.3 and [MS-KILE] sect 3.4.5.4.1 

4422 """ 

4423 # Is confidentiality in use? 

4424 confidentiality = (Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG) and any( 

4425 x.conf_req_flag for x in msgs 

4426 ) 

4427 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4428 # Build token 

4429 tok = KRB_InnerToken( 

4430 TOK_ID=b"\x05\x04", 

4431 root=KRB_GSS_Wrap( 

4432 Flags="AcceptorSubkey" 

4433 + ("+SentByAcceptor" if Context.IsAcceptor else "") 

4434 + ("+Sealed" if confidentiality else ""), 

4435 SND_SEQ=Context.SendSeqNum, 

4436 RRC=0, 

4437 ), 

4438 ) 

4439 Context.SendSeqNum += 1 

4440 # Real separation starts now: RFC4121 sect 4.2.4 

4441 if confidentiality: 

4442 # Confidentiality is requested (see RFC4121 sect 4.3) 

4443 # {"header" | encrypt(plaintext-data | filler | "header")} 

4444 # 0. Roll confounder 

4445 Confounder = os.urandom(Context.KrbSessionKey.ep.blocksize) 

4446 # 1. Concatenate the data to be encrypted 

4447 Data = b"".join(x.data for x in msgs if x.conf_req_flag) 

4448 DataLen = len(Data) 

4449 # 2. Add filler 

4450 # [MS-KILE] sect 3.4.5.4.1 - "For AES-SHA1 ciphers, the EC must not 

4451 # be zero" 

4452 tok.root.EC = ((-DataLen) % Context.KrbSessionKey.ep.blocksize) or 16 

4453 Filler = b"\x00" * tok.root.EC 

4454 Data += Filler 

4455 # 3. Add first 16 octets of the Wrap token "header" 

4456 PlainHeader = bytes(tok)[:16] 

4457 Data += PlainHeader 

4458 # 4. Build 'ToSign', exclusively used for checksum 

4459 ToSign = Confounder 

4460 ToSign += b"".join(x.data for x in msgs if x.sign) 

4461 ToSign += Filler 

4462 ToSign += PlainHeader 

4463 # 5. Finalize token for signing 

4464 # "The RRC field is [...] 28 if encryption is requested." 

4465 tok.root.RRC = 28 

4466 # 6. encrypt() is the encryption operation (which provides for 

4467 # integrity protection) 

4468 Data = Context.KrbSessionKey.encrypt( 

4469 keyusage=Context.SendSealKeyUsage, 

4470 plaintext=Data, 

4471 confounder=Confounder, 

4472 signtext=ToSign, 

4473 ) 

4474 # 7. Rotate 

4475 Data = strrot(Data, tok.root.RRC + tok.root.EC) 

4476 # 8. Split (token and encrypted messages) 

4477 toklen = len(Data) - DataLen 

4478 tok.root.Data = Data[:toklen] 

4479 offset = toklen 

4480 for msg in msgs: 

4481 msglen = len(msg.data) 

4482 if msg.conf_req_flag: 

4483 msg.data = Data[offset : offset + msglen] 

4484 offset += msglen 

4485 return msgs, tok 

4486 else: 

4487 # No confidentiality is requested 

4488 # {"header" | plaintext-data | get_mic(plaintext-data | "header")} 

4489 # 0. Concatenate the data 

4490 Data = b"".join(x.data for x in msgs if x.sign) 

4491 DataLen = len(Data) 

4492 # 1. Add first 16 octets of the Wrap token "header" 

4493 ToSign = Data 

4494 ToSign += bytes(tok)[:16] 

4495 # 2. get_mic() is the checksum operation for the required 

4496 # checksum mechanism 

4497 Mic = Context.KrbSessionKey.make_checksum( 

4498 keyusage=Context.SendSealKeyUsage, 

4499 text=ToSign, 

4500 ) 

4501 # In Wrap tokens without confidentiality, the EC field SHALL be used 

4502 # to encode the number of octets in the trailing checksum 

4503 tok.root.EC = 12 # len(tok.root.Data) == 12 for AES 

4504 # "The RRC field ([RFC4121] section 4.2.5) is 12 if no encryption 

4505 # is requested" 

4506 tok.root.RRC = 12 

4507 # 3. Concat and pack 

4508 for msg in msgs: 

4509 if msg.sign: 

4510 msg.data = b"" 

4511 Data = Data + Mic 

4512 # 4. Rotate 

4513 tok.root.Data = strrot(Data, tok.root.RRC) 

4514 return msgs, tok 

4515 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

4516 from scapy.libs.rfc3961 import ( 

4517 Cipher, 

4518 Hmac_MD5, 

4519 _rfc1964pad, 

4520 decrepit_algorithms, 

4521 ) 

4522 

4523 # Build token 

4524 seq = struct.pack(">I", Context.SendSeqNum) 

4525 tok = KRB_InnerToken( 

4526 TOK_ID=b"\x02\x01", 

4527 root=KRB_GSS_Wrap_RFC1964( 

4528 SGN_ALG="HMAC", 

4529 SEAL_ALG="RC4" if confidentiality else "none", 

4530 SND_SEQ=seq 

4531 + ( 

4532 # See errata 

4533 b"\xff\xff\xff\xff" 

4534 if Context.IsAcceptor 

4535 else b"\x00\x00\x00\x00" 

4536 ), 

4537 ), 

4538 ) 

4539 Context.SendSeqNum += 1 

4540 # 0. Concatenate data 

4541 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

4542 ToEncrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

4543 Kss = Context.KrbSessionKey.key 

4544 # 1. Roll confounder 

4545 Confounder = os.urandom(8) 

4546 # 2. Compute the 'Kseq' key 

4547 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

4548 if Context.KrbSessionKey.etype == 24: # EXP 

4549 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4550 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

4551 else: 

4552 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

4553 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

4554 # 3. Build SGN_CKSUM 

4555 tok.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

4556 keyusage=13, # See errata 

4557 text=bytes(tok)[:8] + Confounder + ToSign, 

4558 )[:8] 

4559 # 4. Populate token + encrypt 

4560 if confidentiality: 

4561 # 'encrypt' is requested 

4562 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

4563 tok.root.CONFOUNDER = rc4.update(Confounder) 

4564 Data = rc4.update(ToEncrypt) 

4565 # Split encrypted data 

4566 offset = 0 

4567 for msg in msgs: 

4568 msglen = len(msg.data) 

4569 if msg.conf_req_flag: 

4570 msg.data = Data[offset : offset + msglen] 

4571 offset += msglen 

4572 else: 

4573 # 'encrypt' is not requested 

4574 tok.root.CONFOUNDER = Confounder 

4575 # 5. Compute the 'Kseq' key 

4576 if Context.KrbSessionKey.etype == 24: # EXP 

4577 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4578 Kseq = Kseq[:7] + b"\xab" * 9 

4579 else: 

4580 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

4581 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

4582 # 6. Encrypt 'SND_SEQ' 

4583 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

4584 tok.root.SND_SEQ = rc4.update(tok.root.SND_SEQ) 

4585 # 7. Include 'InitialContextToken pseudo ASN.1 header' 

4586 tok = KRB_GSSAPI_Token( 

4587 MechType="1.2.840.113554.1.2.2", # Kerberos 5 

4588 innerToken=tok, 

4589 ) 

4590 return msgs, tok 

4591 else: 

4592 raise NotImplementedError 

4593 

4594 def GSS_UnwrapEx(self, Context, msgs, signature): 

4595 """ 

4596 [MS-KILE] sect 3.4.5.5 

4597 

4598 - AES: RFC4121 sect 4.2.6.2 

4599 - HMAC-RC4: RFC4757 sect 7.3 

4600 """ 

4601 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4602 confidentiality = signature.root.Flags.Sealed 

4603 # Real separation starts now: RFC4121 sect 4.2.4 

4604 if confidentiality: 

4605 # 0. Concatenate the data 

4606 Data = signature.root.Data 

4607 Data += b"".join(x.data for x in msgs if x.conf_req_flag) 

4608 # 1. Un-Rotate 

4609 Data = strrot(Data, signature.root.RRC + signature.root.EC, right=False) 

4610 

4611 # 2. Function to build 'ToSign', exclusively used for checksum 

4612 def MakeToSign(Confounder, DecText): 

4613 offset = 0 

4614 # 2.a Confounder 

4615 ToSign = Confounder 

4616 # 2.b Messages 

4617 for msg in msgs: 

4618 msglen = len(msg.data) 

4619 if msg.conf_req_flag: 

4620 ToSign += DecText[offset : offset + msglen] 

4621 offset += msglen 

4622 elif msg.sign: 

4623 ToSign += msg.data 

4624 # 2.c Filler & Padding 

4625 ToSign += DecText[offset:] 

4626 return ToSign 

4627 

4628 # 3. Decrypt 

4629 Data = Context.KrbSessionKey.decrypt( 

4630 keyusage=Context.RecvSealKeyUsage, 

4631 ciphertext=Data, 

4632 presignfunc=MakeToSign, 

4633 ) 

4634 # 4. Split 

4635 Data, f16header = ( 

4636 Data[:-16], 

4637 Data[-16:], 

4638 ) 

4639 # 5. Check header 

4640 hdr = signature.copy() 

4641 hdr.root.RRC = 0 

4642 if f16header != bytes(hdr)[:16]: 

4643 raise ValueError("ERROR: Headers don't match") 

4644 # 6. Split (and ignore filler) 

4645 offset = 0 

4646 for msg in msgs: 

4647 msglen = len(msg.data) 

4648 if msg.conf_req_flag: 

4649 msg.data = Data[offset : offset + msglen] 

4650 offset += msglen 

4651 # Case without msgs 

4652 if len(msgs) == 1 and not msgs[0].data: 

4653 msgs[0].data = Data 

4654 return msgs 

4655 else: 

4656 # No confidentiality is requested 

4657 # 0. Concatenate the data 

4658 Data = signature.root.Data 

4659 Data += b"".join(x.data for x in msgs if x.sign) 

4660 # 1. Un-Rotate 

4661 Data = strrot(Data, signature.root.RRC, right=False) 

4662 # 2. Split 

4663 Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :] 

4664 # "Both the EC field and the RRC field in 

4665 # the token header SHALL be filled with zeroes for the purpose of 

4666 # calculating the checksum." 

4667 ToSign = Data 

4668 hdr = signature.copy() 

4669 hdr.root.RRC = 0 

4670 hdr.root.EC = 0 

4671 # Concatenate the data 

4672 ToSign += bytes(hdr)[:16] 

4673 # 3. Calculate the signature 

4674 sig = Context.KrbSessionKey.make_checksum( 

4675 keyusage=Context.RecvSealKeyUsage, 

4676 text=ToSign, 

4677 ) 

4678 # 4. Compare 

4679 if sig != Mic: 

4680 raise ValueError("ERROR: Checksums don't match") 

4681 # Case without msgs 

4682 if len(msgs) == 1 and not msgs[0].data: 

4683 msgs[0].data = Data 

4684 return msgs 

4685 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

4686 from scapy.libs.rfc3961 import ( 

4687 Cipher, 

4688 Hmac_MD5, 

4689 _rfc1964pad, 

4690 decrepit_algorithms, 

4691 ) 

4692 

4693 # Drop wrapping 

4694 tok = signature.innerToken 

4695 

4696 # Detect confidentiality 

4697 confidentiality = tok.root.SEAL_ALG != 0xFFFF 

4698 

4699 # 0. Concatenate data 

4700 ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

4701 Kss = Context.KrbSessionKey.key 

4702 # 1. Compute the 'Kseq' key 

4703 if Context.KrbSessionKey.etype == 24: # EXP 

4704 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4705 Kseq = Kseq[:7] + b"\xab" * 9 

4706 else: 

4707 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

4708 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

4709 # 2. Decrypt 'SND_SEQ' 

4710 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

4711 seq = rc4.update(tok.root.SND_SEQ)[:4] 

4712 # 3. Compute the 'Kcrypt' key 

4713 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

4714 if Context.KrbSessionKey.etype == 24: # EXP 

4715 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4716 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

4717 else: 

4718 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

4719 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

4720 # 4. Decrypt 

4721 if confidentiality: 

4722 # 'encrypt' was requested 

4723 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

4724 Confounder = rc4.update(tok.root.CONFOUNDER) 

4725 Data = rc4.update(ToDecrypt) 

4726 # Split encrypted data 

4727 offset = 0 

4728 for msg in msgs: 

4729 msglen = len(msg.data) 

4730 if msg.conf_req_flag: 

4731 msg.data = Data[offset : offset + msglen] 

4732 offset += msglen 

4733 else: 

4734 # 'encrypt' was not requested 

4735 Confounder = tok.root.CONFOUNDER 

4736 # 5. Verify SGN_CKSUM 

4737 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

4738 Context.KrbSessionKey.verify_checksum( 

4739 keyusage=13, # See errata 

4740 text=bytes(tok)[:8] + Confounder + ToSign, 

4741 cksum=tok.root.SGN_CKSUM, 

4742 ) 

4743 return msgs 

4744 else: 

4745 raise NotImplementedError 

4746 

4747 def GSS_Init_sec_context( 

4748 self, 

4749 Context: CONTEXT, 

4750 token=None, 

4751 target_name: Optional[str] = None, 

4752 req_flags: Optional[GSS_C_FLAGS] = None, 

4753 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

4754 ): 

4755 if Context is None: 

4756 # New context 

4757 Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags) 

4758 

4759 from scapy.libs.rfc3961 import Key 

4760 

4761 if Context.state == self.STATE.INIT and self.U2U: 

4762 # U2U - Get TGT 

4763 Context.state = self.STATE.CLI_SENT_TGTREQ 

4764 return ( 

4765 Context, 

4766 KRB_GSSAPI_Token( 

4767 MechType="1.2.840.113554.1.2.2.3", # U2U 

4768 innerToken=KRB_InnerToken( 

4769 TOK_ID=b"\x04\x00", 

4770 root=KRB_TGT_REQ(), 

4771 ), 

4772 ), 

4773 GSS_S_CONTINUE_NEEDED, 

4774 ) 

4775 

4776 if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]: 

4777 if not self.UPN: 

4778 raise ValueError("Missing UPN attribute") 

4779 # Do we have a ST? 

4780 if self.ST is None: 

4781 # Client sends an AP-req 

4782 if not self.SPN and not target_name: 

4783 raise ValueError("Missing SPN/target_name attribute") 

4784 additional_tickets = [] 

4785 if self.U2U: 

4786 try: 

4787 # GSSAPI / Kerberos 

4788 tgt_rep = token.root.innerToken.root 

4789 except AttributeError: 

4790 try: 

4791 # Kerberos 

4792 tgt_rep = token.innerToken.root 

4793 except AttributeError: 

4794 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4795 if not isinstance(tgt_rep, KRB_TGT_REP): 

4796 tgt_rep.show() 

4797 raise ValueError("KerberosSSP: Unexpected token !") 

4798 additional_tickets = [tgt_rep.ticket] 

4799 if self.TGT is not None: 

4800 if not self.KEY: 

4801 raise ValueError("Cannot use TGT without the KEY") 

4802 # Use TGT 

4803 res = krb_tgs_req( 

4804 upn=self.UPN, 

4805 spn=self.SPN or target_name, 

4806 ip=self.DC_IP, 

4807 sessionkey=self.KEY, 

4808 ticket=self.TGT, 

4809 additional_tickets=additional_tickets, 

4810 u2u=self.U2U, 

4811 debug=self.debug, 

4812 ) 

4813 else: 

4814 # Ask for TGT then ST 

4815 res = krb_as_and_tgs( 

4816 upn=self.UPN, 

4817 spn=self.SPN or target_name, 

4818 ip=self.DC_IP, 

4819 key=self.KEY, 

4820 password=self.PASSWORD, 

4821 additional_tickets=additional_tickets, 

4822 u2u=self.U2U, 

4823 debug=self.debug, 

4824 ) 

4825 if not res: 

4826 # Failed to retrieve the ticket 

4827 return Context, None, GSS_S_FAILURE 

4828 self.ST, self.KEY = res.tgsrep.ticket, res.sessionkey 

4829 elif not self.KEY: 

4830 raise ValueError("Must provide KEY with ST") 

4831 Context.STSessionKey = self.KEY 

4832 

4833 # Save ServerHostname 

4834 if len(self.ST.sname.nameString) == 2: 

4835 Context.ServerHostname = self.ST.sname.nameString[1].val.decode() 

4836 

4837 # Build the KRB-AP 

4838 apOptions = ASN1_BIT_STRING("000") 

4839 if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG: 

4840 apOptions.set(2, "1") # mutual-required 

4841 if self.U2U: 

4842 apOptions.set(1, "1") # use-session-key 

4843 Context.U2U = True 

4844 ap_req = KRB_AP_REQ( 

4845 apOptions=apOptions, 

4846 ticket=self.ST, 

4847 authenticator=EncryptedData(), 

4848 ) 

4849 

4850 # Get the current time 

4851 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

4852 # Pick a random session key 

4853 Context.KrbSessionKey = Key.new_random_key( 

4854 self.SKEY_TYPE, 

4855 ) 

4856 

4857 # We use a random SendSeqNum 

4858 Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix() 

4859 

4860 # Get the realm of the client 

4861 _, crealm = _parse_upn(self.UPN) 

4862 

4863 # Build and encrypt the full KRB_Authenticator 

4864 ap_req.authenticator.encrypt( 

4865 Context.STSessionKey, 

4866 KRB_Authenticator( 

4867 crealm=crealm, 

4868 cname=PrincipalName.fromUPN(self.UPN), 

4869 # RFC 4121 checksum 

4870 cksum=Checksum( 

4871 cksumtype="KRB-AUTHENTICATOR", 

4872 checksum=KRB_AuthenticatorChecksum( 

4873 # RFC 4121 sect 4.1.1.2 

4874 # "The Bnd field contains the MD5 hash of channel bindings" 

4875 Bnd=( 

4876 chan_bindings.digestMD5() 

4877 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4878 else (b"\x00" * 16) 

4879 ), 

4880 Flags=int(Context.flags), 

4881 ), 

4882 ), 

4883 ctime=ASN1_GENERALIZED_TIME(now_time), 

4884 cusec=ASN1_INTEGER(0), 

4885 subkey=EncryptionKey.fromKey(Context.KrbSessionKey), 

4886 seqNumber=Context.SendSeqNum, 

4887 encAuthorizationData=AuthorizationData( 

4888 seq=[ 

4889 AuthorizationDataItem( 

4890 adType="AD-IF-RELEVANT", 

4891 adData=AuthorizationData( 

4892 seq=[ 

4893 AuthorizationDataItem( 

4894 adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

4895 adData=KERB_AD_RESTRICTION_ENTRY( 

4896 restriction=LSAP_TOKEN_INFO_INTEGRITY( 

4897 MachineID=bytes(RandBin(32)), 

4898 PermanentMachineID=bytes(RandBin(32)), # noqa: E501 

4899 ) 

4900 ), 

4901 ), 

4902 # This isn't documented, but sent on Windows :/ 

4903 AuthorizationDataItem( 

4904 adType="KERB-LOCAL", 

4905 adData=b"\x00" * 16, 

4906 ), 

4907 ] 

4908 + ( 

4909 # Channel bindings 

4910 [ 

4911 AuthorizationDataItem( 

4912 adType="AD-AUTH-DATA-AP-OPTIONS", 

4913 adData=KERB_AUTH_DATA_AP_OPTIONS( 

4914 apOptions="KERB_AP_OPTIONS_CBT" 

4915 ), 

4916 ) 

4917 ] 

4918 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4919 else [] 

4920 ) 

4921 ), 

4922 ) 

4923 ] 

4924 ), 

4925 ), 

4926 ) 

4927 Context.state = self.STATE.CLI_SENT_APREQ 

4928 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

4929 # Raw kerberos DCE-STYLE 

4930 return Context, ap_req, GSS_S_CONTINUE_NEEDED 

4931 else: 

4932 # Kerberos wrapper 

4933 return ( 

4934 Context, 

4935 KRB_GSSAPI_Token( 

4936 innerToken=KRB_InnerToken( 

4937 root=ap_req, 

4938 ) 

4939 ), 

4940 GSS_S_CONTINUE_NEEDED, 

4941 ) 

4942 

4943 elif Context.state == self.STATE.CLI_SENT_APREQ: 

4944 if isinstance(token, KRB_AP_REP): 

4945 # Raw AP_REP was passed 

4946 ap_rep = token 

4947 else: 

4948 try: 

4949 # GSSAPI / Kerberos 

4950 ap_rep = token.root.innerToken.root 

4951 except AttributeError: 

4952 try: 

4953 # Kerberos 

4954 ap_rep = token.innerToken.root 

4955 except AttributeError: 

4956 try: 

4957 # Raw kerberos DCE-STYLE 

4958 ap_rep = token.root 

4959 except AttributeError: 

4960 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4961 if not isinstance(ap_rep, KRB_AP_REP): 

4962 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4963 # Retrieve SessionKey 

4964 repPart = ap_rep.encPart.decrypt(Context.STSessionKey) 

4965 if repPart.subkey is not None: 

4966 Context.SessionKey = repPart.subkey.keyvalue.val 

4967 Context.KrbSessionKey = repPart.subkey.toKey() 

4968 # OK ! 

4969 Context.state = self.STATE.CLI_RCVD_APREP 

4970 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

4971 # [MS-KILE] sect 3.4.5.1 

4972 # The client MUST generate an additional AP exchange reply message 

4973 # exactly as the server would as the final message to send to the 

4974 # server. 

4975 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

4976 cli_ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

4977 cli_ap_rep.encPart.encrypt( 

4978 Context.STSessionKey, 

4979 EncAPRepPart( 

4980 ctime=ASN1_GENERALIZED_TIME(now_time), 

4981 seqNumber=repPart.seqNumber, 

4982 subkey=None, 

4983 ), 

4984 ) 

4985 return Context, cli_ap_rep, GSS_S_COMPLETE 

4986 return Context, None, GSS_S_COMPLETE 

4987 elif ( 

4988 Context.state == self.STATE.CLI_RCVD_APREP 

4989 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

4990 ): 

4991 # DCE_STYLE with SPNEGOSSP 

4992 return Context, None, GSS_S_COMPLETE 

4993 else: 

4994 raise ValueError("KerberosSSP: Unknown state") 

4995 

4996 def GSS_Accept_sec_context( 

4997 self, 

4998 Context: CONTEXT, 

4999 token=None, 

5000 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5001 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5002 ): 

5003 if Context is None: 

5004 # New context 

5005 Context = self.CONTEXT(IsAcceptor=True, req_flags=req_flags) 

5006 

5007 from scapy.libs.rfc3961 import Key 

5008 import scapy.layers.msrpce.mspac # noqa: F401 

5009 

5010 if Context.state == self.STATE.INIT: 

5011 if self.UPN and self.SPN: 

5012 raise ValueError("Cannot use SPN and UPN at the same time !") 

5013 if self.SPN and self.TGT: 

5014 raise ValueError("Cannot use TGT with SPN.") 

5015 if self.UPN and not self.TGT: 

5016 # UPN is provided: use U2U 

5017 res = krb_as_req( 

5018 self.UPN, 

5019 self.DC_IP, 

5020 key=self.KEY, 

5021 password=self.PASSWORD, 

5022 ) 

5023 self.TGT, self.KEY = res.asrep.ticket, res.sessionkey 

5024 

5025 # Server receives AP-req, sends AP-rep 

5026 if isinstance(token, KRB_AP_REQ): 

5027 # Raw AP_REQ was passed 

5028 ap_req = token 

5029 else: 

5030 try: 

5031 # GSSAPI/Kerberos 

5032 ap_req = token.root.innerToken.root 

5033 except AttributeError: 

5034 try: 

5035 # Kerberos 

5036 ap_req = token.innerToken.root 

5037 except AttributeError: 

5038 try: 

5039 # Raw kerberos 

5040 ap_req = token.root 

5041 except AttributeError: 

5042 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5043 

5044 if isinstance(ap_req, KRB_TGT_REQ): 

5045 # Special U2U case 

5046 Context.U2U = True 

5047 return ( 

5048 None, 

5049 KRB_GSSAPI_Token( 

5050 MechType="1.2.840.113554.1.2.2.3", # U2U 

5051 innerToken=KRB_InnerToken( 

5052 TOK_ID=b"\x04\x01", 

5053 root=KRB_TGT_REP( 

5054 ticket=self.TGT, 

5055 ), 

5056 ), 

5057 ), 

5058 GSS_S_CONTINUE_NEEDED, 

5059 ) 

5060 elif not isinstance(ap_req, KRB_AP_REQ): 

5061 ap_req.show() 

5062 raise ValueError("Unexpected type in KerberosSSP") 

5063 if not self.KEY: 

5064 raise ValueError("Missing KEY attribute") 

5065 

5066 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5067 

5068 # If using a UPN, require U2U 

5069 if self.UPN and ap_req.apOptions.val[1] != "1": # use-session-key 

5070 # Required but not provided. Return an error 

5071 Context.U2U = True 

5072 err = KRB_GSSAPI_Token( 

5073 innerToken=KRB_InnerToken( 

5074 TOK_ID=b"\x03\x00", 

5075 root=KRB_ERROR( 

5076 errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED", 

5077 stime=ASN1_GENERALIZED_TIME(now_time), 

5078 realm=ap_req.ticket.realm, 

5079 sname=ap_req.ticket.sname, 

5080 eData=KRB_TGT_REP( 

5081 ticket=self.TGT, 

5082 ), 

5083 ), 

5084 ) 

5085 ) 

5086 return Context, err, GSS_S_CONTINUE_NEEDED 

5087 

5088 # Validate the 'serverName' of the ticket. 

5089 sname = ap_req.ticket.getSPN() 

5090 our_sname = self.SPN or self.UPN 

5091 if not _spn_are_equal(our_sname, sname): 

5092 warning("KerberosSSP: bad server name: %s != %s" % (sname, our_sname)) 

5093 err = KRB_GSSAPI_Token( 

5094 innerToken=KRB_InnerToken( 

5095 TOK_ID=b"\x03\x00", 

5096 root=KRB_ERROR( 

5097 errorCode="KRB_AP_ERR_BADMATCH", 

5098 stime=ASN1_GENERALIZED_TIME(now_time), 

5099 realm=ap_req.ticket.realm, 

5100 sname=ap_req.ticket.sname, 

5101 eData=None, 

5102 ), 

5103 ) 

5104 ) 

5105 return Context, err, GSS_S_BAD_MECH 

5106 

5107 # Decrypt the ticket 

5108 try: 

5109 tkt = ap_req.ticket.encPart.decrypt(self.KEY) 

5110 except ValueError as ex: 

5111 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5112 err = KRB_GSSAPI_Token( 

5113 innerToken=KRB_InnerToken( 

5114 TOK_ID=b"\x03\x00", 

5115 root=KRB_ERROR( 

5116 errorCode="KRB_AP_ERR_MODIFIED", 

5117 stime=ASN1_GENERALIZED_TIME(now_time), 

5118 realm=ap_req.ticket.realm, 

5119 sname=ap_req.ticket.sname, 

5120 eData=None, 

5121 ), 

5122 ) 

5123 ) 

5124 return Context, err, GSS_S_DEFECTIVE_TOKEN 

5125 

5126 # Store information about the user in the Context 

5127 if tkt.authorizationData and tkt.authorizationData.seq: 

5128 # Get AD-IF-RELEVANT 

5129 adIfRelevant = tkt.authorizationData.getAuthData(0x1) 

5130 if adIfRelevant: 

5131 # Get AD-WIN2K-PAC 

5132 Context.PAC = adIfRelevant.getAuthData(0x80) 

5133 

5134 # Get AP-REQ session key 

5135 Context.STSessionKey = tkt.key.toKey() 

5136 authenticator = ap_req.authenticator.decrypt(Context.STSessionKey) 

5137 

5138 # Compute an application session key ([MS-KILE] sect 3.1.1.2) 

5139 subkey = None 

5140 if ap_req.apOptions.val[2] == "1": # mutual-required 

5141 appkey = Key.new_random_key( 

5142 self.SKEY_TYPE, 

5143 ) 

5144 Context.KrbSessionKey = appkey 

5145 Context.SessionKey = appkey.key 

5146 subkey = EncryptionKey.fromKey(appkey) 

5147 else: 

5148 Context.KrbSessionKey = self.KEY 

5149 Context.SessionKey = self.KEY.key 

5150 

5151 # Eventually process the "checksum" 

5152 if authenticator.cksum and authenticator.cksum.cksumtype == 0x8003: 

5153 # KRB-Authenticator 

5154 authcksum = authenticator.cksum.checksum 

5155 Context.flags = authcksum.Flags 

5156 # Check channel bindings 

5157 if ( 

5158 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5159 and chan_bindings.digestMD5() != authcksum.Bnd 

5160 and not ( 

5161 GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS in req_flags 

5162 and authcksum.Bnd == GSS_C_NO_CHANNEL_BINDINGS 

5163 ) 

5164 ): 

5165 # Channel binding checks failed. 

5166 return Context, None, GSS_S_BAD_BINDINGS 

5167 elif ( 

5168 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5169 and GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS not in req_flags 

5170 ): 

5171 # Uhoh, we required channel bindings 

5172 return Context, None, GSS_S_BAD_BINDINGS 

5173 

5174 # Build response (RFC4120 sect 3.2.4) 

5175 ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5176 ap_rep.encPart.encrypt( 

5177 Context.STSessionKey, 

5178 EncAPRepPart( 

5179 ctime=authenticator.ctime, 

5180 cusec=authenticator.cusec, 

5181 seqNumber=None, 

5182 subkey=subkey, 

5183 ), 

5184 ) 

5185 Context.state = self.STATE.SRV_SENT_APREP 

5186 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5187 # [MS-KILE] sect 3.4.5.1 

5188 return Context, ap_rep, GSS_S_CONTINUE_NEEDED 

5189 return Context, ap_rep, GSS_S_COMPLETE # success 

5190 elif ( 

5191 Context.state == self.STATE.SRV_SENT_APREP 

5192 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5193 ): 

5194 # [MS-KILE] sect 3.4.5.1 

5195 # The server MUST receive the additional AP exchange reply message and 

5196 # verify that the message is constructed correctly. 

5197 if not token: 

5198 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5199 # Server receives AP-req, sends AP-rep 

5200 if isinstance(token, KRB_AP_REP): 

5201 # Raw AP_REP was passed 

5202 ap_rep = token 

5203 else: 

5204 try: 

5205 # GSSAPI/Kerberos 

5206 ap_rep = token.root.innerToken.root 

5207 except AttributeError: 

5208 try: 

5209 # Raw Kerberos 

5210 ap_rep = token.root 

5211 except AttributeError: 

5212 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5213 # Decrypt the AP-REP 

5214 try: 

5215 ap_rep.encPart.decrypt(Context.STSessionKey) 

5216 except ValueError as ex: 

5217 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5218 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5219 return Context, None, GSS_S_COMPLETE # success 

5220 else: 

5221 raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state)) 

5222 

5223 def GSS_Passive( 

5224 self, 

5225 Context: CONTEXT, 

5226 token=None, 

5227 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5228 ): 

5229 if Context is None: 

5230 Context = self.CONTEXT(True) 

5231 Context.passive = True 

5232 

5233 if Context.state == self.STATE.INIT or ( 

5234 # In DCE/RPC, there's an extra AP-REP sent from the client. 

5235 Context.state == self.STATE.SRV_SENT_APREP 

5236 and req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5237 ): 

5238 Context, _, status = self.GSS_Accept_sec_context( 

5239 Context, token, req_flags=req_flags 

5240 ) 

5241 if status in [GSS_S_CONTINUE_NEEDED, GSS_S_COMPLETE]: 

5242 Context.state = self.STATE.CLI_SENT_APREQ 

5243 else: 

5244 Context.state = self.STATE.FAILED 

5245 return Context, status 

5246 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5247 Context, _, status = self.GSS_Init_sec_context( 

5248 Context, token, req_flags=req_flags 

5249 ) 

5250 if status == GSS_S_COMPLETE: 

5251 Context.state = self.STATE.SRV_SENT_APREP 

5252 else: 

5253 Context.state == self.STATE.FAILED 

5254 return Context, status 

5255 

5256 # Unknown state. Don't crash though. 

5257 return Context, GSS_S_FAILURE 

5258 

5259 def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False): 

5260 if Context.IsAcceptor is not IsAcceptor: 

5261 return 

5262 # Swap everything 

5263 Context.SendSealKeyUsage, Context.RecvSealKeyUsage = ( 

5264 Context.RecvSealKeyUsage, 

5265 Context.SendSealKeyUsage, 

5266 ) 

5267 Context.SendSignKeyUsage, Context.RecvSignKeyUsage = ( 

5268 Context.RecvSignKeyUsage, 

5269 Context.SendSignKeyUsage, 

5270 ) 

5271 Context.IsAcceptor = not Context.IsAcceptor 

5272 

5273 def LegsAmount(self, Context: CONTEXT): 

5274 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5275 return 4 

5276 else: 

5277 return 2 

5278 

5279 def MaximumSignatureLength(self, Context: CONTEXT): 

5280 if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG: 

5281 # TODO: support DES 

5282 if Context.KrbSessionKey.etype in [17, 18]: # AES 

5283 return 76 

5284 elif Context.KrbSessionKey.etype in [23, 24]: # RC4_HMAC 

5285 return 45 

5286 else: 

5287 raise NotImplementedError 

5288 else: 

5289 return 28 

5290 

5291 def canMechListMIC(self, Context: CONTEXT): 

5292 return bool(Context.KrbSessionKey)