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

1611 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- User to User Kerberos Authentication: draft-ietf-cat-user2user-03 

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

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

19 draft-ietf-kitten-iakerb-03 

20- Kerberos Protocol Extensions: [MS-KILE] 

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

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

23 

24 

25.. note:: 

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

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

28 

29Example decryption:: 

30 

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

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

33 83c0a87a9cc0a87a11c209005854f6ab2392c25bd650182014b6e00000000001316a8201\ 

34 2d30820129a103020105a20302010aa3633061304ca103020102a24504433041a0030201\ 

35 12a23a043848484decb01c9b62a1cabfbc3f2d1ed85aa5e093ba8358a8cea34d4393af93\ 

36 bf211e274fa58e814878db9f0d7a28d94e7327660db4f3704b3011a10402020080a20904\ 

37 073005a0030101ffa481b73081b4a00703050040810010a1123010a003020101a1093007\ 

38 1b0577696e3124a20e1b0c444f4d41494e2e4c4f43414ca321301fa003020102a1183016\ 

39 1b066b72627467741b0c444f4d41494e2e4c4f43414ca511180f32303337303931333032\ 

40 343830355aa611180f32303337303931333032343830355aa7060204701cc5d1a8153013\ 

41 0201120201110201170201180202ff79020103a91d301b3019a003020114a11204105749\ 

42 4e31202020202020202020202020")) 

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

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

45 e87127a819d42e69b5e22de0ddc63da80096d")) 

46 >>> enc.decrypt(k) 

47""" 

48 

49from collections import namedtuple, deque 

50from datetime import datetime, timedelta, timezone 

51from enum import IntEnum 

52 

53import os 

54import re 

55import socket 

56import struct 

57 

58from scapy.error import warning 

59import scapy.asn1.mib # noqa: F401 

60from scapy.asn1.ber import BER_id_dec, BER_Decoding_Error 

61from scapy.asn1.asn1 import ( 

62 ASN1_BIT_STRING, 

63 ASN1_BOOLEAN, 

64 ASN1_Class, 

65 ASN1_GENERAL_STRING, 

66 ASN1_GENERALIZED_TIME, 

67 ASN1_INTEGER, 

68 ASN1_STRING, 

69 ASN1_Codecs, 

70) 

71from scapy.asn1fields import ( 

72 ASN1F_BOOLEAN, 

73 ASN1F_CHOICE, 

74 ASN1F_FLAGS, 

75 ASN1F_GENERAL_STRING, 

76 ASN1F_GENERALIZED_TIME, 

77 ASN1F_INTEGER, 

78 ASN1F_OID, 

79 ASN1F_PACKET, 

80 ASN1F_SEQUENCE, 

81 ASN1F_SEQUENCE_OF, 

82 ASN1F_STRING, 

83 ASN1F_STRING_PacketField, 

84 ASN1F_enum_INTEGER, 

85 ASN1F_optional, 

86) 

87from scapy.asn1packet import ASN1_Packet 

88from scapy.automaton import Automaton, ATMT 

89from scapy.config import conf 

90from scapy.compat import bytes_encode 

91from scapy.error import log_runtime 

92from scapy.fields import ( 

93 ConditionalField, 

94 FieldLenField, 

95 FlagsField, 

96 IntEnumField, 

97 LEIntEnumField, 

98 LenField, 

99 LEShortEnumField, 

100 LEShortField, 

101 LongField, 

102 MultipleTypeField, 

103 PacketField, 

104 PacketLenField, 

105 PacketListField, 

106 PadField, 

107 ShortEnumField, 

108 ShortField, 

109 StrField, 

110 StrFieldUtf16, 

111 StrFixedLenEnumField, 

112 XByteField, 

113 XLEIntField, 

114 XLEIntEnumField, 

115 XLEShortField, 

116 XStrFixedLenField, 

117 XStrLenField, 

118 XStrField, 

119) 

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

121from scapy.supersocket import StreamSocket, SuperSocket 

122from scapy.utils import strrot, strxor 

123from scapy.volatile import GeneralizedTime, RandNum, RandBin 

124 

125from scapy.layers.gssapi import ( 

126 GSSAPI_BLOB, 

127 GSS_C_FLAGS, 

128 GSS_C_NO_CHANNEL_BINDINGS, 

129 GSS_S_BAD_BINDINGS, 

130 GSS_S_BAD_MECH, 

131 GSS_S_COMPLETE, 

132 GSS_S_CONTINUE_NEEDED, 

133 GSS_S_DEFECTIVE_TOKEN, 

134 GSS_S_FAILURE, 

135 GSS_S_FLAGS, 

136 GssChannelBindings, 

137 SSP, 

138 _GSSAPI_OIDS, 

139 _GSSAPI_SIGNATURE_OIDS, 

140) 

141from scapy.layers.inet import TCP, UDP 

142from scapy.layers.smb import _NV_VERSION 

143from scapy.layers.smb2 import STATUS_ERREF 

144from scapy.layers.x509 import X509_AlgorithmIdentifier 

145 

146# Redirect exports from RFC3961 

147try: 

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

149except ImportError: 

150 pass 

151 

152# Typing imports 

153from typing import ( 

154 Optional, 

155) 

156 

157 

158# kerberos APPLICATION 

159 

160 

161class ASN1_Class_KRB(ASN1_Class): 

162 name = "Kerberos" 

163 # APPLICATION + CONSTRUCTED = 0x40 | 0x20 

164 Token = 0x60 | 0 # GSSAPI 

165 Ticket = 0x60 | 1 

166 Authenticator = 0x60 | 2 

167 EncTicketPart = 0x60 | 3 

168 AS_REQ = 0x60 | 10 

169 AS_REP = 0x60 | 11 

170 TGS_REQ = 0x60 | 12 

171 TGS_REP = 0x60 | 13 

172 AP_REQ = 0x60 | 14 

173 AP_REP = 0x60 | 15 

174 PRIV = 0x60 | 21 

175 CRED = 0x60 | 22 

176 EncASRepPart = 0x60 | 25 

177 EncTGSRepPart = 0x60 | 26 

178 EncAPRepPart = 0x60 | 27 

179 EncKrbPrivPart = 0x60 | 28 

180 EncKrbCredPart = 0x60 | 29 

181 ERROR = 0x60 | 30 

182 

183 

184# RFC4120 sect 5.2 

185 

186 

187KerberosString = ASN1F_GENERAL_STRING 

188Realm = KerberosString 

189Int32 = ASN1F_INTEGER 

190UInt32 = ASN1F_INTEGER 

191 

192_PRINCIPAL_NAME_TYPES = { 

193 0: "NT-UNKNOWN", 

194 1: "NT-PRINCIPAL", 

195 2: "NT-SRV-INST", 

196 3: "NT-SRV-HST", 

197 4: "NT-SRV-XHST", 

198 5: "NT-UID", 

199 6: "NT-X500-PRINCIPAL", 

200 7: "NT-SMTP-NAME", 

201 10: "NT-ENTERPRISE", 

202} 

203 

204 

205class PrincipalName(ASN1_Packet): 

206 ASN1_codec = ASN1_Codecs.BER 

207 ASN1_root = ASN1F_SEQUENCE( 

208 ASN1F_enum_INTEGER( 

209 "nameType", 

210 0, 

211 _PRINCIPAL_NAME_TYPES, 

212 explicit_tag=0xA0, 

213 ), 

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

215 ) 

216 

217 def toString(self): 

218 """ 

219 Convert a PrincipalName back into its string representation. 

220 """ 

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

222 

223 @staticmethod 

224 def fromUPN(upn: str): 

225 """ 

226 Create a PrincipalName from a UPN string. 

227 """ 

228 user, _ = _parse_upn(upn) 

229 return PrincipalName( 

230 nameString=[ASN1_GENERAL_STRING(user)], 

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

232 ) 

233 

234 @staticmethod 

235 def fromSPN(spn: str): 

236 """ 

237 Create a PrincipalName from a SPN string. 

238 """ 

239 spn, _ = _parse_spn(spn) 

240 if spn.startswith("krbtgt"): 

241 return PrincipalName( 

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

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

244 ) 

245 elif "/" in spn: 

246 return PrincipalName( 

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

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

249 ) 

250 else: 

251 # In case of U2U 

252 return PrincipalName( 

253 nameString=[ASN1_GENERAL_STRING(spn)], 

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

255 ) 

256 

257 

258KerberosTime = ASN1F_GENERALIZED_TIME 

259Microseconds = ASN1F_INTEGER 

260 

261 

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

263 

264_KRB_E_TYPES = { 

265 1: "DES-CBC-CRC", 

266 2: "DES-CBC-MD4", 

267 3: "DES-CBC-MD5", 

268 5: "DES3-CBC-MD5", 

269 7: "DES3-CBC-SHA1", 

270 9: "DSAWITHSHA1-CMSOID", 

271 10: "MD5WITHRSAENCRYPTION-CMSOID", 

272 11: "SHA1WITHRSAENCRYPTION-CMSOID", 

273 12: "RC2CBC-ENVOID", 

274 13: "RSAENCRYPTION-ENVOID", 

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

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

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

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

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

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

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

282 23: "RC4-HMAC", 

283 24: "RC4-HMAC-EXP", 

284 25: "CAMELLIA128-CTS-CMAC", 

285 26: "CAMELLIA256-CTS-CMAC", 

286} 

287 

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

289 

290_KRB_S_TYPES = { 

291 1: "CRC32", 

292 2: "RSA-MD4", 

293 3: "RSA-MD4-DES", 

294 4: "DES-MAC", 

295 5: "DES-MAC-K", 

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

297 7: "RSA-MD5", 

298 8: "RSA-MD5-DES", 

299 9: "RSA-MD5-DES3", 

300 10: "SHA1", 

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

302 13: "HMAC-SHA1-DES3", 

303 14: "SHA1", 

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

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

306 17: "CMAC-CAMELLIA128", 

307 18: "CMAC-CAMELLIA256", 

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

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

310 # RFC 4121 

311 0x8003: "KRB-AUTHENTICATOR", 

312 # [MS-KILE] 

313 0xFFFFFF76: "MD5", 

314 -138: "MD5", 

315} 

316 

317 

318class EncryptedData(ASN1_Packet): 

319 ASN1_codec = ASN1_Codecs.BER 

320 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

324 ) 

325 

326 def get_usage(self): 

327 """ 

328 Get current key usage number and encrypted class 

329 """ 

330 # RFC 4120 sect 7.5.1 

331 if self.underlayer: 

332 if isinstance(self.underlayer, PADATA): 

333 patype = self.underlayer.padataType 

334 if patype == 2: 

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

336 return 1, PA_ENC_TS_ENC 

337 elif patype == 138: 

338 # RFC6113 PA-ENC-TS-ENC 

339 return 54, PA_ENC_TS_ENC 

340 elif isinstance(self.underlayer, KRB_Ticket): 

341 # AS-REP Ticket and TGS-REP Ticket 

342 return 2, EncTicketPart 

343 elif isinstance(self.underlayer, KRB_AS_REP): 

344 # AS-REP encrypted part 

345 return 3, EncASRepPart 

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

347 self.underlayer.underlayer, PADATA 

348 ): 

349 # TGS-REQ PA-TGS-REQ Authenticator 

350 return 7, KRB_Authenticator 

351 elif isinstance(self.underlayer, KRB_TGS_REP): 

352 # TGS-REP encrypted part 

353 return 8, EncTGSRepPart 

354 elif isinstance(self.underlayer, KRB_AP_REQ): 

355 # AP-REQ Authenticator 

356 return 11, KRB_Authenticator 

357 elif isinstance(self.underlayer, KRB_AP_REP): 

358 # AP-REP encrypted part 

359 return 12, EncAPRepPart 

360 elif isinstance(self.underlayer, KRB_PRIV): 

361 # KRB-PRIV encrypted part 

362 return 13, EncKrbPrivPart 

363 elif isinstance(self.underlayer, KRB_CRED): 

364 # KRB-CRED encrypted part 

365 return 14, EncKrbCredPart 

366 elif isinstance(self.underlayer, KrbFastArmoredReq): 

367 # KEY_USAGE_FAST_ENC 

368 return 51, KrbFastReq 

369 elif isinstance(self.underlayer, KrbFastArmoredRep): 

370 # KEY_USAGE_FAST_REP 

371 return 52, KrbFastResponse 

372 raise ValueError( 

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

374 ) 

375 

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

377 """ 

378 Decrypt and return the data contained in cipher. 

379 

380 :param key: the key to use for decryption 

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

382 Guessed otherwise 

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

384 Guessed otherwise (or bytes) 

385 """ 

386 if key_usage_number is None: 

387 key_usage_number, cls = self.get_usage() 

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

389 if cls: 

390 try: 

391 return cls(d) 

392 except BER_Decoding_Error: 

393 if cls == EncASRepPart: 

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

395 # "Compatibility note: Some implementations unconditionally send an 

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

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

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

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

400 try: 

401 res = EncTGSRepPart(d) 

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

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

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

405 log_runtime.warning( 

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

407 ) 

408 return res 

409 except BER_Decoding_Error: 

410 pass 

411 raise 

412 return d 

413 

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

415 """ 

416 Encrypt text and set it into cipher. 

417 

418 :param key: the key to use for encryption 

419 :param text: the bytes value to encode 

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

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

422 Guessed otherwise 

423 """ 

424 if key_usage_number is None: 

425 key_usage_number = self.get_usage()[0] 

426 self.etype = key.etype 

427 self.cipher = ASN1_STRING( 

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

429 ) 

430 

431 

432class EncryptionKey(ASN1_Packet): 

433 ASN1_codec = ASN1_Codecs.BER 

434 ASN1_root = ASN1F_SEQUENCE( 

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

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

437 ) 

438 

439 def toKey(self): 

440 from scapy.libs.rfc3961 import Key 

441 

442 return Key( 

443 etype=self.keytype.val, 

444 key=self.keyvalue.val, 

445 ) 

446 

447 @classmethod 

448 def fromKey(self, key): 

449 return EncryptionKey( 

450 keytype=key.etype, 

451 keyvalue=key.key, 

452 ) 

453 

454 

455class _Checksum_Field(ASN1F_STRING_PacketField): 

456 def m2i(self, pkt, s): 

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

458 if not val[0].val: 

459 return val 

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

461 # Special case per RFC 4121 

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

463 return val 

464 

465 

466class Checksum(ASN1_Packet): 

467 ASN1_codec = ASN1_Codecs.BER 

468 ASN1_root = ASN1F_SEQUENCE( 

469 ASN1F_enum_INTEGER( 

470 "cksumtype", 

471 0, 

472 _KRB_S_TYPES, 

473 explicit_tag=0xA0, 

474 ), 

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

476 ) 

477 

478 def get_usage(self): 

479 """ 

480 Get current key usage number 

481 """ 

482 # RFC 4120 sect 7.5.1 

483 if self.underlayer: 

484 if isinstance(self.underlayer, KRB_Authenticator): 

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

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

487 return 6 

488 elif isinstance(self.underlayer, PA_FOR_USER): 

489 # [MS-SFU] sect 2.2.1 

490 return 17 

491 elif isinstance(self.underlayer, PA_S4U_X509_USER): 

492 # [MS-SFU] sect 2.2.2 

493 return 26 

494 elif isinstance(self.underlayer, AD_KDCIssued): 

495 # AD-KDC-ISSUED checksum 

496 return 19 

497 elif isinstance(self.underlayer, KrbFastArmoredReq): 

498 # KEY_USAGE_FAST_REQ_CHKSUM 

499 return 50 

500 elif isinstance(self.underlayer, KrbFastFinished): 

501 # KEY_USAGE_FAST_FINISHED 

502 return 53 

503 raise ValueError( 

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

505 ) 

506 

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

508 """ 

509 Decrypt and return the data contained in cipher. 

510 

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

512 :param text: the bytes to verify 

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

514 Guessed otherwise 

515 """ 

516 if key_usage_number is None: 

517 key_usage_number = self.get_usage() 

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

519 

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

521 """ 

522 Encrypt text and set it into cipher. 

523 

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

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

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 self.cksumtype = cksumtype or key.cksumtype 

532 self.checksum = ASN1_STRING( 

533 key.make_checksum( 

534 keyusage=key_usage_number, 

535 text=text, 

536 cksumtype=self.cksumtype, 

537 ) 

538 ) 

539 

540 

541KerberosFlags = ASN1F_FLAGS 

542 

543_ADDR_TYPES = { 

544 # RFC4120 sect 7.5.3 

545 0x02: "IPv4", 

546 0x03: "Directional", 

547 0x05: "ChaosNet", 

548 0x06: "XNS", 

549 0x07: "ISO", 

550 0x0C: "DECNET Phase IV", 

551 0x10: "AppleTalk DDP", 

552 0x14: "NetBios", 

553 0x18: "IPv6", 

554} 

555 

556 

557class HostAddress(ASN1_Packet): 

558 ASN1_codec = ASN1_Codecs.BER 

559 ASN1_root = ASN1F_SEQUENCE( 

560 ASN1F_enum_INTEGER( 

561 "addrType", 

562 0, 

563 _ADDR_TYPES, 

564 explicit_tag=0xA0, 

565 ), 

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

567 ) 

568 

569 

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

571 name, [], HostAddress, **kwargs 

572) 

573 

574 

575_AUTHORIZATIONDATA_VALUES = { 

576 # Filled below 

577} 

578 

579 

580class _AuthorizationData_value_Field(ASN1F_STRING_PacketField): 

581 def m2i(self, pkt, s): 

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

583 if not val[0].val: 

584 return val 

585 if pkt.adType.val in _AUTHORIZATIONDATA_VALUES: 

586 return ( 

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

588 val[1], 

589 ) 

590 return val 

591 

592 

593_AD_TYPES = { 

594 # RFC4120 sect 7.5.4 

595 1: "AD-IF-RELEVANT", 

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

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

598 4: "AD-KDC-ISSUED", 

599 5: "AD-AND-OR", 

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

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

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

603 64: "OSF-DCE", 

604 65: "SESAME", 

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

606 128: "AD-WIN2K-PAC", 

607 129: "AD-ETYPE-NEGOTIATION", 

608 # [MS-KILE] additions 

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

610 142: "KERB-LOCAL", 

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

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

613} 

614 

615 

616class AuthorizationDataItem(ASN1_Packet): 

617 ASN1_codec = ASN1_Codecs.BER 

618 ASN1_root = ASN1F_SEQUENCE( 

619 ASN1F_enum_INTEGER( 

620 "adType", 

621 0, 

622 _AD_TYPES, 

623 explicit_tag=0xA0, 

624 ), 

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

626 ) 

627 

628 

629class AuthorizationData(ASN1_Packet): 

630 ASN1_codec = ASN1_Codecs.BER 

631 ASN1_root = ASN1F_SEQUENCE_OF( 

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

633 ) 

634 

635 def getAuthData(self, adType): 

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

637 

638 

639AD_IF_RELEVANT = AuthorizationData 

640_AUTHORIZATIONDATA_VALUES[1] = AD_IF_RELEVANT 

641 

642 

643class AD_KDCIssued(ASN1_Packet): 

644 ASN1_codec = ASN1_Codecs.BER 

645 ASN1_root = ASN1F_SEQUENCE( 

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

647 ASN1F_optional( 

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

649 ), 

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

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

652 ) 

653 

654 

655_AUTHORIZATIONDATA_VALUES[4] = AD_KDCIssued 

656 

657 

658class AD_AND_OR(ASN1_Packet): 

659 ASN1_codec = ASN1_Codecs.BER 

660 ASN1_root = ASN1F_SEQUENCE( 

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

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

663 ) 

664 

665 

666_AUTHORIZATIONDATA_VALUES[5] = AD_AND_OR 

667 

668ADMANDATORYFORKDC = AuthorizationData 

669_AUTHORIZATIONDATA_VALUES[8] = ADMANDATORYFORKDC 

670 

671 

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

673_PADATA_TYPES = { 

674 1: "PA-TGS-REQ", 

675 2: "PA-ENC-TIMESTAMP", 

676 3: "PA-PW-SALT", 

677 11: "PA-ETYPE-INFO", 

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

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

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

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

682 19: "PA-ETYPE-INFO2", 

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

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

685 128: "PA-PAC-REQUEST", 

686 129: "PA-FOR-USER", 

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

688 131: "PA-FOR-CHECK_DUPS", 

689 132: "PA-AS-CHECKSUM", 

690 133: "PA-FX-COOKIE", 

691 134: "PA-AUTHENTICATION-SET", 

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

693 136: "PA-FX-FAST", 

694 137: "PA-FX-ERROR", 

695 138: "PA-ENCRYPTED-CHALLENGE", 

696 141: "PA-OTP-CHALLENGE", 

697 142: "PA-OTP-REQUEST", 

698 143: "PA-OTP-CONFIRM", 

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

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

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

702 147: "PA-PKINIT-KX", 

703 148: "PA-PKU2U-NAME", 

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

705 150: "PA-AS-FRESHNESS", 

706 151: "PA-SPAKE", 

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

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

709 165: "PA-SUPPORTED-ENCTYPES", 

710 166: "PA-EXTENDED-ERROR", 

711 167: "PA-PAC-OPTIONS", 

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

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

714} 

715 

716_PADATA_CLASSES = { 

717 # Filled elsewhere in this file 

718} 

719 

720 

721# RFC4120 

722 

723 

724class _PADATA_value_Field(ASN1F_STRING_PacketField): 

725 """ 

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

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

728 """ 

729 

730 def m2i(self, pkt, s): 

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

732 if pkt.padataType.val in _PADATA_CLASSES: 

733 cls = _PADATA_CLASSES[pkt.padataType.val] 

734 if isinstance(cls, tuple): 

735 parent = pkt.underlayer or pkt.parent 

736 is_reply = False 

737 if parent is not None: 

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

739 is_reply = True 

740 else: 

741 parent = parent.underlayer or parent.parent 

742 is_reply = isinstance(parent, KRB_ERROR) 

743 cls = cls[is_reply] 

744 if not val[0].val: 

745 return val 

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

747 return val 

748 

749 

750class PADATA(ASN1_Packet): 

751 ASN1_codec = ASN1_Codecs.BER 

752 ASN1_root = ASN1F_SEQUENCE( 

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

754 _PADATA_value_Field( 

755 "padataValue", 

756 "", 

757 explicit_tag=0xA2, 

758 ), 

759 ) 

760 

761 

762# RFC 4120 sect 5.2.7.2 

763 

764 

765class PA_ENC_TS_ENC(ASN1_Packet): 

766 ASN1_codec = ASN1_Codecs.BER 

767 ASN1_root = ASN1F_SEQUENCE( 

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

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

770 ) 

771 

772 

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

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

775 

776 

777# RFC 4120 sect 5.2.7.4 

778 

779 

780class ETYPE_INFO_ENTRY(ASN1_Packet): 

781 ASN1_codec = ASN1_Codecs.BER 

782 ASN1_root = ASN1F_SEQUENCE( 

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

784 ASN1F_optional( 

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

786 ), 

787 ) 

788 

789 

790class ETYPE_INFO(ASN1_Packet): 

791 ASN1_codec = ASN1_Codecs.BER 

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

793 

794 

795_PADATA_CLASSES[11] = ETYPE_INFO 

796 

797# RFC 4120 sect 5.2.7.5 

798 

799 

800class ETYPE_INFO_ENTRY2(ASN1_Packet): 

801 ASN1_codec = ASN1_Codecs.BER 

802 ASN1_root = ASN1F_SEQUENCE( 

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

804 ASN1F_optional( 

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

806 ), 

807 ASN1F_optional( 

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

809 ), 

810 ) 

811 

812 

813class ETYPE_INFO2(ASN1_Packet): 

814 ASN1_codec = ASN1_Codecs.BER 

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

816 

817 

818_PADATA_CLASSES[19] = ETYPE_INFO2 

819 

820 

821# RFC8636 - PKINIT Algorithm Agility 

822 

823 

824class TD_CMS_DIGEST_ALGORITHMS(ASN1_Packet): 

825 ASN1_codec = ASN1_Codecs.BER 

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

827 

828 

829_PADATA_CLASSES[111] = TD_CMS_DIGEST_ALGORITHMS 

830 

831 

832# PADATA Extended with RFC6113 

833 

834 

835class PA_AUTHENTICATION_SET_ELEM(ASN1_Packet): 

836 ASN1_codec = ASN1_Codecs.BER 

837 ASN1_root = ASN1F_SEQUENCE( 

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

839 ASN1F_optional( 

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

841 ), 

842 ASN1F_optional( 

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

844 ), 

845 ) 

846 

847 

848class PA_AUTHENTICATION_SET(ASN1_Packet): 

849 ASN1_codec = ASN1_Codecs.BER 

850 ASN1_root = ASN1F_SEQUENCE_OF( 

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

852 ) 

853 

854 

855_PADATA_CLASSES[134] = PA_AUTHENTICATION_SET 

856 

857 

858# [MS-KILE] sect 2.2.3 

859 

860 

861class PA_PAC_REQUEST(ASN1_Packet): 

862 ASN1_codec = ASN1_Codecs.BER 

863 ASN1_root = ASN1F_SEQUENCE( 

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

865 ) 

866 

867 

868_PADATA_CLASSES[128] = PA_PAC_REQUEST 

869 

870 

871# [MS-KILE] sect 2.2.5 

872 

873 

874class LSAP_TOKEN_INFO_INTEGRITY(Packet): 

875 fields_desc = [ 

876 FlagsField( 

877 "Flags", 

878 0, 

879 -32, 

880 { 

881 0x00000001: "UAC-Restricted", 

882 }, 

883 ), 

884 LEIntEnumField( 

885 "TokenIL", 

886 0x00002000, 

887 { 

888 0x00000000: "Untrusted", 

889 0x00001000: "Low", 

890 0x00002000: "Medium", 

891 0x00003000: "High", 

892 0x00004000: "System", 

893 0x00005000: "Protected process", 

894 }, 

895 ), 

896 XStrFixedLenField("MachineID", b"", length=32), 

897 ] 

898 

899 

900# [MS-KILE] sect 2.2.6 

901 

902 

903class _KerbAdRestrictionEntry_Field(ASN1F_STRING_PacketField): 

904 def m2i(self, pkt, s): 

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

906 if not val[0].val: 

907 return val 

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

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

910 return val 

911 

912 

913class KERB_AD_RESTRICTION_ENTRY(ASN1_Packet): 

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

915 ASN1_codec = ASN1_Codecs.BER 

916 ASN1_root = ASN1F_SEQUENCE( 

917 ASN1F_SEQUENCE( 

918 ASN1F_enum_INTEGER( 

919 "restrictionType", 

920 0, 

921 {0: "LSAP_TOKEN_INFO_INTEGRITY"}, 

922 explicit_tag=0xA0, 

923 ), 

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

925 ) 

926 ) 

927 

928 

929_AUTHORIZATIONDATA_VALUES[141] = KERB_AD_RESTRICTION_ENTRY 

930 

931 

932# [MS-KILE] sect 3.2.5.8 

933 

934 

935class KERB_AUTH_DATA_AP_OPTIONS(Packet): 

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

937 fields_desc = [ 

938 LEIntEnumField( 

939 "apOptions", 

940 0x4000, 

941 { 

942 0x4000: "KERB_AP_OPTIONS_CBT", 

943 0x8000: "KERB_AP_OPTIONS_UNVERIFIED_TARGET_NAME", 

944 }, 

945 ), 

946 ] 

947 

948 

949_AUTHORIZATIONDATA_VALUES[143] = KERB_AUTH_DATA_AP_OPTIONS 

950 

951 

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

953 

954 

955class KERB_AUTH_DATA_CLIENT_TARGET(Packet): 

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

957 fields_desc = [ 

958 StrFieldUtf16("spn", ""), 

959 ] 

960 

961 

962_AUTHORIZATIONDATA_VALUES[144] = KERB_AUTH_DATA_CLIENT_TARGET 

963 

964 

965# RFC6806 sect 6 

966 

967 

968class KERB_AD_LOGIN_ALIAS(ASN1_Packet): 

969 ASN1_codec = ASN1_Codecs.BER 

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

971 

972 

973_AUTHORIZATIONDATA_VALUES[80] = KERB_AD_LOGIN_ALIAS 

974 

975 

976# [MS-KILE] sect 2.2.8 

977 

978 

979class PA_SUPPORTED_ENCTYPES(Packet): 

980 fields_desc = [ 

981 FlagsField( 

982 "flags", 

983 0, 

984 -32, 

985 [ 

986 "DES-CBC-CRC", 

987 "DES-CBC-MD5", 

988 "RC4-HMAC", 

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

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

991 ] 

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

993 + [ 

994 "FAST-supported", 

995 "Compount-identity-supported", 

996 "Claims-supported", 

997 "Resource-SID-compression-disabled", 

998 ], 

999 ) 

1000 ] 

1001 

1002 

1003_PADATA_CLASSES[165] = PA_SUPPORTED_ENCTYPES 

1004 

1005# [MS-KILE] sect 2.2.10 

1006 

1007 

1008class PA_PAC_OPTIONS(ASN1_Packet): 

1009 ASN1_codec = ASN1_Codecs.BER 

1010 ASN1_root = ASN1F_SEQUENCE( 

1011 KerberosFlags( 

1012 "options", 

1013 "", 

1014 [ 

1015 "Claims", 

1016 "Branch-Aware", 

1017 "Forward-to-Full-DC", 

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

1019 ], 

1020 explicit_tag=0xA0, 

1021 ) 

1022 ) 

1023 

1024 

1025_PADATA_CLASSES[167] = PA_PAC_OPTIONS 

1026 

1027# [MS-KILE] sect 2.2.11 

1028 

1029 

1030class KERB_KEY_LIST_REQ(ASN1_Packet): 

1031 ASN1_codec = ASN1_Codecs.BER 

1032 ASN1_root = ASN1F_SEQUENCE_OF( 

1033 "keytypes", 

1034 [], 

1035 ASN1F_enum_INTEGER("", 0, _KRB_E_TYPES), 

1036 ) 

1037 

1038 

1039_PADATA_CLASSES[161] = KERB_KEY_LIST_REQ 

1040 

1041# [MS-KILE] sect 2.2.12 

1042 

1043 

1044class KERB_KEY_LIST_REP(ASN1_Packet): 

1045 ASN1_codec = ASN1_Codecs.BER 

1046 ASN1_root = ASN1F_SEQUENCE_OF( 

1047 "keys", 

1048 [], 

1049 ASN1F_PACKET("", None, EncryptionKey), 

1050 ) 

1051 

1052 

1053_PADATA_CLASSES[162] = KERB_KEY_LIST_REP 

1054 

1055# [MS-KILE] sect 2.2.13 

1056 

1057 

1058class KERB_SUPERSEDED_BY_USER(ASN1_Packet): 

1059 ASN1_codec = ASN1_Codecs.BER 

1060 ASN1_root = ASN1F_SEQUENCE( 

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

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

1063 ) 

1064 

1065 

1066_PADATA_CLASSES[170] = KERB_SUPERSEDED_BY_USER 

1067 

1068 

1069# [MS-KILE] sect 2.2.14 

1070 

1071 

1072class KERB_DMSA_KEY_PACKAGE(ASN1_Packet): 

1073 ASN1_codec = ASN1_Codecs.BER 

1074 ASN1_root = ASN1F_SEQUENCE( 

1075 ASN1F_SEQUENCE_OF( 

1076 "currentKeys", 

1077 [], 

1078 ASN1F_PACKET("", None, EncryptionKey), 

1079 explicit_tag=0xA0, 

1080 ), 

1081 ASN1F_optional( 

1082 ASN1F_SEQUENCE_OF( 

1083 "previousKeys", 

1084 [], 

1085 ASN1F_PACKET("", None, EncryptionKey), 

1086 explicit_tag=0xA1, 

1087 ), 

1088 ), 

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

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

1091 ) 

1092 

1093 

1094_PADATA_CLASSES[171] = KERB_DMSA_KEY_PACKAGE 

1095 

1096 

1097# RFC6113 sect 5.4.1 

1098 

1099 

1100class _KrbFastArmor_value_Field(ASN1F_STRING_PacketField): 

1101 def m2i(self, pkt, s): 

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

1103 if not val[0].val: 

1104 return val 

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

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

1107 return val 

1108 

1109 

1110class KrbFastArmor(ASN1_Packet): 

1111 ASN1_codec = ASN1_Codecs.BER 

1112 ASN1_root = ASN1F_SEQUENCE( 

1113 ASN1F_enum_INTEGER( 

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

1115 ), 

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

1117 ) 

1118 

1119 

1120# RFC6113 sect 5.4.2 

1121 

1122 

1123class KrbFastArmoredReq(ASN1_Packet): 

1124 ASN1_codec = ASN1_Codecs.BER 

1125 ASN1_root = ASN1F_SEQUENCE( 

1126 ASN1F_SEQUENCE( 

1127 ASN1F_optional( 

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

1129 ), 

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

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

1132 ) 

1133 ) 

1134 

1135 

1136class PA_FX_FAST_REQUEST(ASN1_Packet): 

1137 ASN1_codec = ASN1_Codecs.BER 

1138 ASN1_root = ASN1F_CHOICE( 

1139 "armoredData", 

1140 ASN1_STRING(""), 

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

1142 ) 

1143 

1144 

1145# RFC6113 sect 5.4.3 

1146 

1147 

1148class KrbFastArmoredRep(ASN1_Packet): 

1149 ASN1_codec = ASN1_Codecs.BER 

1150 ASN1_root = ASN1F_SEQUENCE( 

1151 ASN1F_SEQUENCE( 

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

1153 ) 

1154 ) 

1155 

1156 

1157class PA_FX_FAST_REPLY(ASN1_Packet): 

1158 ASN1_codec = ASN1_Codecs.BER 

1159 ASN1_root = ASN1F_CHOICE( 

1160 "armoredData", 

1161 ASN1_STRING(""), 

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

1163 ) 

1164 

1165 

1166class KrbFastFinished(ASN1_Packet): 

1167 ASN1_codec = ASN1_Codecs.BER 

1168 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

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

1174 ) 

1175 

1176 

1177class KrbFastResponse(ASN1_Packet): 

1178 ASN1_codec = ASN1_Codecs.BER 

1179 ASN1_root = ASN1F_SEQUENCE( 

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

1181 ASN1F_optional( 

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

1183 ), 

1184 ASN1F_optional( 

1185 ASN1F_PACKET( 

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

1187 ) 

1188 ), 

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

1190 ) 

1191 

1192 

1193_PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY) 

1194 

1195# RFC 4556 

1196 

1197 

1198# sect 3.2.1 

1199 

1200 

1201class ExternalPrincipalIdentifier(ASN1_Packet): 

1202 ASN1_codec = ASN1_Codecs.BER 

1203 ASN1_root = ASN1F_SEQUENCE( 

1204 ASN1F_optional( 

1205 ASN1F_STRING("subjectName", "", implicit_tag=0xA0), 

1206 ), 

1207 ASN1F_optional( 

1208 ASN1F_STRING("issuerAndSerialNumber", "", implicit_tag=0xA1), 

1209 ), 

1210 ASN1F_optional( 

1211 ASN1F_STRING("subjectKeyIdentifier", "", implicit_tag=0xA2), 

1212 ), 

1213 ) 

1214 

1215 

1216class PA_PK_AS_REQ(ASN1_Packet): 

1217 ASN1_codec = ASN1_Codecs.BER 

1218 ASN1_root = ASN1F_SEQUENCE( 

1219 ASN1F_STRING("signedAuthpack", "", implicit_tag=0xA0), 

1220 ASN1F_optional( 

1221 ASN1F_SEQUENCE_OF( 

1222 "trustedCertifiers", 

1223 [ExternalPrincipalIdentifier()], 

1224 ExternalPrincipalIdentifier, 

1225 explicit_tag=0xA1, 

1226 ), 

1227 ), 

1228 ASN1F_optional( 

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

1230 ), 

1231 ) 

1232 

1233 

1234_PADATA_CLASSES[16] = PA_PK_AS_REQ 

1235 

1236# sect 3.2.3 

1237 

1238 

1239class DHRepInfo(ASN1_Packet): 

1240 ASN1_codec = ASN1_Codecs.BER 

1241 ASN1_root = ASN1F_SEQUENCE( 

1242 ASN1F_STRING("dhSignedData", "", implicit_tag=0xA0), 

1243 ASN1F_optional( 

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

1245 ), 

1246 ) 

1247 

1248 

1249class EncKeyPack(ASN1_Packet): 

1250 ASN1_codec = ASN1_Codecs.BER 

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

1252 

1253 

1254class PA_PK_AS_REP(ASN1_Packet): 

1255 ASN1_codec = ASN1_Codecs.BER 

1256 ASN1_root = ASN1F_CHOICE( 

1257 "rep", 

1258 ASN1_STRING(""), 

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

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

1261 ) 

1262 

1263 

1264_PADATA_CLASSES[17] = PA_PK_AS_REP 

1265 

1266# [MS-SFU] 

1267 

1268 

1269# sect 2.2.1 

1270class PA_FOR_USER(ASN1_Packet): 

1271 ASN1_codec = ASN1_Codecs.BER 

1272 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

1277 ) 

1278 

1279 

1280_PADATA_CLASSES[129] = PA_FOR_USER 

1281 

1282 

1283# sect 2.2.2 

1284 

1285 

1286class S4UUserID(ASN1_Packet): 

1287 ASN1_codec = ASN1_Codecs.BER 

1288 ASN1_root = ASN1F_SEQUENCE( 

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

1290 ASN1F_optional( 

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

1292 ), 

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

1294 ASN1F_optional( 

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

1296 ), 

1297 ASN1F_optional( 

1298 ASN1F_FLAGS( 

1299 "options", 

1300 "", 

1301 [ 

1302 "reserved", 

1303 "KDC_CHECK_LOGON_HOUR_RESTRICTIONS", 

1304 "USE_REPLY_KEY_USAGE", 

1305 "NT_AUTH_POLICY_NOT_REQUIRED", 

1306 "UNCONDITIONAL_DELEGATION", 

1307 ], 

1308 explicit_tag=0xA4, 

1309 ) 

1310 ), 

1311 ) 

1312 

1313 

1314class PA_S4U_X509_USER(ASN1_Packet): 

1315 ASN1_codec = ASN1_Codecs.BER 

1316 ASN1_root = ASN1F_SEQUENCE( 

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

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

1319 ) 

1320 

1321 

1322_PADATA_CLASSES[130] = PA_S4U_X509_USER 

1323 

1324 

1325# Back to RFC4120 

1326 

1327# sect 5.10 

1328KRB_MSG_TYPES = { 

1329 1: "Ticket", 

1330 2: "Authenticator", 

1331 3: "EncTicketPart", 

1332 10: "AS-REQ", 

1333 11: "AS-REP", 

1334 12: "TGS-REQ", 

1335 13: "TGS-REP", 

1336 14: "AP-REQ", 

1337 15: "AP-REP", 

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

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

1340 20: "KRB-SAFE", 

1341 21: "KRB-PRIV", 

1342 22: "KRB-CRED", 

1343 25: "EncASRepPart", 

1344 26: "EncTGSRepPart", 

1345 27: "EncAPRepPart", 

1346 28: "EncKrbPrivPart", 

1347 29: "EnvKrbCredPart", 

1348 30: "KRB-ERROR", 

1349} 

1350 

1351# sect 5.3 

1352 

1353 

1354class KRB_Ticket(ASN1_Packet): 

1355 ASN1_codec = ASN1_Codecs.BER 

1356 ASN1_root = ASN1F_SEQUENCE( 

1357 ASN1F_SEQUENCE( 

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

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

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

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

1362 ), 

1363 implicit_tag=ASN1_Class_KRB.Ticket, 

1364 ) 

1365 

1366 def getSPN(self): 

1367 return "%s@%s" % ( 

1368 self.sname.toString(), 

1369 self.realm.val.decode(), 

1370 ) 

1371 

1372 

1373class TransitedEncoding(ASN1_Packet): 

1374 ASN1_codec = ASN1_Codecs.BER 

1375 ASN1_root = ASN1F_SEQUENCE( 

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

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

1378 ) 

1379 

1380 

1381_TICKET_FLAGS = [ 

1382 "reserved", 

1383 "forwardable", 

1384 "forwarded", 

1385 "proxiable", 

1386 "proxy", 

1387 "may-postdate", 

1388 "postdated", 

1389 "invalid", 

1390 "renewable", 

1391 "initial", 

1392 "pre-authent", 

1393 "hw-authent", 

1394 "transited-since-policy-checked", 

1395 "ok-as-delegate", 

1396 "unused", 

1397 "canonicalize", # RFC6806 

1398 "anonymous", # RFC6112 + RFC8129 

1399] 

1400 

1401 

1402class EncTicketPart(ASN1_Packet): 

1403 ASN1_codec = ASN1_Codecs.BER 

1404 ASN1_root = ASN1F_SEQUENCE( 

1405 ASN1F_SEQUENCE( 

1406 KerberosFlags( 

1407 "flags", 

1408 "", 

1409 _TICKET_FLAGS, 

1410 explicit_tag=0xA0, 

1411 ), 

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

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

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

1415 ASN1F_PACKET( 

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

1417 ), 

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

1419 ASN1F_optional( 

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

1421 ), 

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

1423 ASN1F_optional( 

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

1425 ), 

1426 ASN1F_optional( 

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

1428 ), 

1429 ASN1F_optional( 

1430 ASN1F_PACKET( 

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

1432 ), 

1433 ), 

1434 ), 

1435 implicit_tag=ASN1_Class_KRB.EncTicketPart, 

1436 ) 

1437 

1438 

1439# sect 5.4.1 

1440 

1441 

1442class KRB_KDC_REQ_BODY(ASN1_Packet): 

1443 ASN1_codec = ASN1_Codecs.BER 

1444 ASN1_root = ASN1F_SEQUENCE( 

1445 KerberosFlags( 

1446 "kdcOptions", 

1447 "", 

1448 [ 

1449 "reserved", 

1450 "forwardable", 

1451 "forwarded", 

1452 "proxiable", 

1453 "proxy", 

1454 "allow-postdate", 

1455 "postdated", 

1456 "unused7", 

1457 "renewable", 

1458 "unused9", 

1459 "unused10", 

1460 "opt-hardware-auth", 

1461 "unused12", 

1462 "unused13", 

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

1464 "canonicalize", # RFC6806 

1465 "request-anonymous", # RFC6112 + RFC8129 

1466 ] 

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

1468 + [ 

1469 "disable-transited-check", 

1470 "renewable-ok", 

1471 "enc-tkt-in-skey", 

1472 "unused29", 

1473 "renew", 

1474 "validate", 

1475 ], 

1476 explicit_tag=0xA0, 

1477 ), 

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

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

1480 ASN1F_optional( 

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

1482 ), 

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

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

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

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

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

1488 ASN1F_optional( 

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

1490 ), 

1491 ASN1F_optional( 

1492 ASN1F_PACKET( 

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

1494 ), 

1495 ), 

1496 ASN1F_optional( 

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

1498 ), 

1499 ) 

1500 

1501 

1502KRB_KDC_REQ = ASN1F_SEQUENCE( 

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

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

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

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

1507) 

1508 

1509 

1510class KrbFastReq(ASN1_Packet): 

1511 # RFC6113 sect 5.4.2 

1512 ASN1_codec = ASN1_Codecs.BER 

1513 ASN1_root = ASN1F_SEQUENCE( 

1514 KerberosFlags( 

1515 "fastOptions", 

1516 "", 

1517 [ 

1518 "RESERVED", 

1519 "hide-client-names", 

1520 ] 

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

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

1523 explicit_tag=0xA0, 

1524 ), 

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

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

1527 ) 

1528 

1529 

1530class KRB_AS_REQ(ASN1_Packet): 

1531 ASN1_codec = ASN1_Codecs.BER 

1532 ASN1_root = ASN1F_SEQUENCE( 

1533 KRB_KDC_REQ, 

1534 implicit_tag=ASN1_Class_KRB.AS_REQ, 

1535 ) 

1536 

1537 

1538class KRB_TGS_REQ(ASN1_Packet): 

1539 ASN1_codec = ASN1_Codecs.BER 

1540 ASN1_root = ASN1F_SEQUENCE( 

1541 KRB_KDC_REQ, 

1542 implicit_tag=ASN1_Class_KRB.TGS_REQ, 

1543 ) 

1544 msgType = ASN1_INTEGER(12) 

1545 

1546 

1547# sect 5.4.2 

1548 

1549KRB_KDC_REP = ASN1F_SEQUENCE( 

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

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

1552 ASN1F_optional( 

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

1554 ), 

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

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

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

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

1559) 

1560 

1561 

1562class KRB_AS_REP(ASN1_Packet): 

1563 ASN1_codec = ASN1_Codecs.BER 

1564 ASN1_root = ASN1F_SEQUENCE( 

1565 KRB_KDC_REP, 

1566 implicit_tag=ASN1_Class_KRB.AS_REP, 

1567 ) 

1568 

1569 

1570class KRB_TGS_REP(ASN1_Packet): 

1571 ASN1_codec = ASN1_Codecs.BER 

1572 ASN1_root = ASN1F_SEQUENCE( 

1573 KRB_KDC_REP, 

1574 implicit_tag=ASN1_Class_KRB.TGS_REP, 

1575 ) 

1576 

1577 def getUPN(self): 

1578 return "%s@%s" % ( 

1579 self.cname.toString(), 

1580 self.crealm.val.decode(), 

1581 ) 

1582 

1583 

1584class LastReqItem(ASN1_Packet): 

1585 ASN1_codec = ASN1_Codecs.BER 

1586 ASN1_root = ASN1F_SEQUENCE( 

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

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

1589 ) 

1590 

1591 

1592EncKDCRepPart = ASN1F_SEQUENCE( 

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

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

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

1596 ASN1F_optional( 

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

1598 ), 

1599 KerberosFlags( 

1600 "flags", 

1601 "", 

1602 _TICKET_FLAGS, 

1603 explicit_tag=0xA4, 

1604 ), 

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

1606 ASN1F_optional( 

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

1608 ), 

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

1610 ASN1F_optional( 

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

1612 ), 

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

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

1615 ASN1F_optional( 

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

1617 ), 

1618 # RFC6806 sect 11 

1619 ASN1F_optional( 

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

1621 ), 

1622) 

1623 

1624 

1625class EncASRepPart(ASN1_Packet): 

1626 ASN1_codec = ASN1_Codecs.BER 

1627 ASN1_root = ASN1F_SEQUENCE( 

1628 EncKDCRepPart, 

1629 implicit_tag=ASN1_Class_KRB.EncASRepPart, 

1630 ) 

1631 

1632 

1633class EncTGSRepPart(ASN1_Packet): 

1634 ASN1_codec = ASN1_Codecs.BER 

1635 ASN1_root = ASN1F_SEQUENCE( 

1636 EncKDCRepPart, 

1637 implicit_tag=ASN1_Class_KRB.EncTGSRepPart, 

1638 ) 

1639 

1640 

1641# sect 5.5.1 

1642 

1643 

1644class KRB_AP_REQ(ASN1_Packet): 

1645 ASN1_codec = ASN1_Codecs.BER 

1646 ASN1_root = ASN1F_SEQUENCE( 

1647 ASN1F_SEQUENCE( 

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

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

1650 KerberosFlags( 

1651 "apOptions", 

1652 "", 

1653 [ 

1654 "reserved", 

1655 "use-session-key", 

1656 "mutual-required", 

1657 ], 

1658 explicit_tag=0xA2, 

1659 ), 

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

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

1662 ), 

1663 implicit_tag=ASN1_Class_KRB.AP_REQ, 

1664 ) 

1665 

1666 

1667_PADATA_CLASSES[1] = KRB_AP_REQ 

1668 

1669 

1670class KRB_Authenticator(ASN1_Packet): 

1671 ASN1_codec = ASN1_Codecs.BER 

1672 ASN1_root = ASN1F_SEQUENCE( 

1673 ASN1F_SEQUENCE( 

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

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

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

1677 ASN1F_optional( 

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

1679 ), 

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

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

1682 ASN1F_optional( 

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

1684 ), 

1685 ASN1F_optional( 

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

1687 ), 

1688 ASN1F_optional( 

1689 ASN1F_PACKET( 

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

1691 ), 

1692 ), 

1693 ), 

1694 implicit_tag=ASN1_Class_KRB.Authenticator, 

1695 ) 

1696 

1697 

1698# sect 5.5.2 

1699 

1700 

1701class KRB_AP_REP(ASN1_Packet): 

1702 ASN1_codec = ASN1_Codecs.BER 

1703 ASN1_root = ASN1F_SEQUENCE( 

1704 ASN1F_SEQUENCE( 

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

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

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

1708 ), 

1709 implicit_tag=ASN1_Class_KRB.AP_REP, 

1710 ) 

1711 

1712 

1713class EncAPRepPart(ASN1_Packet): 

1714 ASN1_codec = ASN1_Codecs.BER 

1715 ASN1_root = ASN1F_SEQUENCE( 

1716 ASN1F_SEQUENCE( 

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

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

1719 ASN1F_optional( 

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

1721 ), 

1722 ASN1F_optional( 

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

1724 ), 

1725 ), 

1726 implicit_tag=ASN1_Class_KRB.EncAPRepPart, 

1727 ) 

1728 

1729 

1730# sect 5.7 

1731 

1732 

1733class KRB_PRIV(ASN1_Packet): 

1734 ASN1_codec = ASN1_Codecs.BER 

1735 ASN1_root = ASN1F_SEQUENCE( 

1736 ASN1F_SEQUENCE( 

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

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

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

1740 ), 

1741 implicit_tag=ASN1_Class_KRB.PRIV, 

1742 ) 

1743 

1744 

1745class EncKrbPrivPart(ASN1_Packet): 

1746 ASN1_codec = ASN1_Codecs.BER 

1747 ASN1_root = ASN1F_SEQUENCE( 

1748 ASN1F_SEQUENCE( 

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

1750 ASN1F_optional( 

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

1752 ), 

1753 ASN1F_optional( 

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

1755 ), 

1756 ASN1F_optional( 

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

1758 ), 

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

1760 ASN1F_optional( 

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

1762 ), 

1763 ), 

1764 implicit_tag=ASN1_Class_KRB.EncKrbPrivPart, 

1765 ) 

1766 

1767 

1768# sect 5.8 

1769 

1770 

1771class KRB_CRED(ASN1_Packet): 

1772 ASN1_codec = ASN1_Codecs.BER 

1773 ASN1_root = ASN1F_SEQUENCE( 

1774 ASN1F_SEQUENCE( 

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

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

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

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

1779 ), 

1780 implicit_tag=ASN1_Class_KRB.CRED, 

1781 ) 

1782 

1783 

1784class KrbCredInfo(ASN1_Packet): 

1785 ASN1_codec = ASN1_Codecs.BER 

1786 ASN1_root = ASN1F_SEQUENCE( 

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

1788 ASN1F_optional( 

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

1790 ), 

1791 ASN1F_optional( 

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

1793 ), 

1794 ASN1F_optional( 

1795 KerberosFlags( 

1796 "flags", 

1797 None, 

1798 _TICKET_FLAGS, 

1799 explicit_tag=0xA3, 

1800 ), 

1801 ), 

1802 ASN1F_optional( 

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

1804 ), 

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

1806 ASN1F_optional( 

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

1808 ), 

1809 ASN1F_optional( 

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

1811 ), 

1812 ASN1F_optional( 

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

1814 ), 

1815 ASN1F_optional( 

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

1817 ), 

1818 ASN1F_optional( 

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

1820 ), 

1821 ) 

1822 

1823 

1824class EncKrbCredPart(ASN1_Packet): 

1825 ASN1_codec = ASN1_Codecs.BER 

1826 ASN1_root = ASN1F_SEQUENCE( 

1827 ASN1F_SEQUENCE( 

1828 ASN1F_SEQUENCE_OF( 

1829 "ticketInfo", 

1830 [KrbCredInfo()], 

1831 KrbCredInfo, 

1832 explicit_tag=0xA0, 

1833 ), 

1834 ASN1F_optional( 

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

1836 ), 

1837 ASN1F_optional( 

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

1839 ), 

1840 ASN1F_optional( 

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

1842 ), 

1843 ASN1F_optional( 

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

1845 ), 

1846 ASN1F_optional( 

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

1848 ), 

1849 ), 

1850 implicit_tag=ASN1_Class_KRB.EncKrbCredPart, 

1851 ) 

1852 

1853 

1854# sect 5.9.1 

1855 

1856 

1857class MethodData(ASN1_Packet): 

1858 ASN1_codec = ASN1_Codecs.BER 

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

1860 

1861 

1862class _KRBERROR_data_Field(ASN1F_STRING_PacketField): 

1863 def m2i(self, pkt, s): 

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

1865 if not val[0].val: 

1866 return val 

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

1868 # 14: KDC_ERR_ETYPE_NOSUPP 

1869 # 24: KDC_ERR_PREAUTH_FAILED 

1870 # 25: KDC_ERR_PREAUTH_REQUIRED 

1871 # 36: KRB_AP_ERR_BADMATCH 

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

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

1874 # 6: KDC_ERR_C_PRINCIPAL_UNKNOWN 

1875 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

1876 # 12: KDC_ERR_POLICY 

1877 # 13: KDC_ERR_BADOPTION 

1878 # 18: KDC_ERR_CLIENT_REVOKED 

1879 # 29: KDC_ERR_SVC_UNAVAILABLE 

1880 # 41: KRB_AP_ERR_MODIFIED 

1881 # 60: KRB_ERR_GENERIC 

1882 try: 

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

1884 except BER_Decoding_Error: 

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

1886 # Some types can also happen in FAST sessions 

1887 # 18: KDC_ERR_CLIENT_REVOKED 

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

1889 elif pkt.errorCode.val == 7: 

1890 # This looks like an undocumented structure. 

1891 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

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

1893 raise 

1894 elif pkt.errorCode.val == 69: 

1895 # KRB_AP_ERR_USER_TO_USER_REQUIRED 

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

1897 return val 

1898 

1899 

1900class KRB_ERROR(ASN1_Packet): 

1901 ASN1_codec = ASN1_Codecs.BER 

1902 ASN1_root = ASN1F_SEQUENCE( 

1903 ASN1F_SEQUENCE( 

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

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

1906 ASN1F_optional( 

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

1908 ), 

1909 ASN1F_optional( 

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

1911 ), 

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

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

1914 ASN1F_enum_INTEGER( 

1915 "errorCode", 

1916 0, 

1917 { 

1918 # RFC4120 sect 7.5.9 

1919 0: "KDC_ERR_NONE", 

1920 1: "KDC_ERR_NAME_EXP", 

1921 2: "KDC_ERR_SERVICE_EXP", 

1922 3: "KDC_ERR_BAD_PVNO", 

1923 4: "KDC_ERR_C_OLD_MAST_KVNO", 

1924 5: "KDC_ERR_S_OLD_MAST_KVNO", 

1925 6: "KDC_ERR_C_PRINCIPAL_UNKNOWN", 

1926 7: "KDC_ERR_S_PRINCIPAL_UNKNOWN", 

1927 8: "KDC_ERR_PRINCIPAL_NOT_UNIQUE", 

1928 9: "KDC_ERR_NULL_KEY", 

1929 10: "KDC_ERR_CANNOT_POSTDATE", 

1930 11: "KDC_ERR_NEVER_VALID", 

1931 12: "KDC_ERR_POLICY", 

1932 13: "KDC_ERR_BADOPTION", 

1933 14: "KDC_ERR_ETYPE_NOSUPP", 

1934 15: "KDC_ERR_SUMTYPE_NOSUPP", 

1935 16: "KDC_ERR_PADATA_TYPE_NOSUPP", 

1936 17: "KDC_ERR_TRTYPE_NOSUPP", 

1937 18: "KDC_ERR_CLIENT_REVOKED", 

1938 19: "KDC_ERR_SERVICE_REVOKED", 

1939 20: "KDC_ERR_TGT_REVOKED", 

1940 21: "KDC_ERR_CLIENT_NOTYET", 

1941 22: "KDC_ERR_SERVICE_NOTYET", 

1942 23: "KDC_ERR_KEY_EXPIRED", 

1943 24: "KDC_ERR_PREAUTH_FAILED", 

1944 25: "KDC_ERR_PREAUTH_REQUIRED", 

1945 26: "KDC_ERR_SERVER_NOMATCH", 

1946 27: "KDC_ERR_MUST_USE_USER2USER", 

1947 28: "KDC_ERR_PATH_NOT_ACCEPTED", 

1948 29: "KDC_ERR_SVC_UNAVAILABLE", 

1949 31: "KRB_AP_ERR_BAD_INTEGRITY", 

1950 32: "KRB_AP_ERR_TKT_EXPIRED", 

1951 33: "KRB_AP_ERR_TKT_NYV", 

1952 34: "KRB_AP_ERR_REPEAT", 

1953 35: "KRB_AP_ERR_NOT_US", 

1954 36: "KRB_AP_ERR_BADMATCH", 

1955 37: "KRB_AP_ERR_SKEW", 

1956 38: "KRB_AP_ERR_BADADDR", 

1957 39: "KRB_AP_ERR_BADVERSION", 

1958 40: "KRB_AP_ERR_MSG_TYPE", 

1959 41: "KRB_AP_ERR_MODIFIED", 

1960 42: "KRB_AP_ERR_BADORDER", 

1961 44: "KRB_AP_ERR_BADKEYVER", 

1962 45: "KRB_AP_ERR_NOKEY", 

1963 46: "KRB_AP_ERR_MUT_FAIL", 

1964 47: "KRB_AP_ERR_BADDIRECTION", 

1965 48: "KRB_AP_ERR_METHOD", 

1966 49: "KRB_AP_ERR_BADSEQ", 

1967 50: "KRB_AP_ERR_INAPP_CKSUM", 

1968 51: "KRB_AP_PATH_NOT_ACCEPTED", 

1969 52: "KRB_ERR_RESPONSE_TOO_BIG", 

1970 60: "KRB_ERR_GENERIC", 

1971 61: "KRB_ERR_FIELD_TOOLONG", 

1972 62: "KDC_ERROR_CLIENT_NOT_TRUSTED", 

1973 63: "KDC_ERROR_KDC_NOT_TRUSTED", 

1974 64: "KDC_ERROR_INVALID_SIG", 

1975 65: "KDC_ERR_KEY_TOO_WEAK", 

1976 66: "KDC_ERR_CERTIFICATE_MISMATCH", 

1977 67: "KRB_AP_ERR_NO_TGT", 

1978 68: "KDC_ERR_WRONG_REALM", 

1979 69: "KRB_AP_ERR_USER_TO_USER_REQUIRED", 

1980 70: "KDC_ERR_CANT_VERIFY_CERTIFICATE", 

1981 71: "KDC_ERR_INVALID_CERTIFICATE", 

1982 72: "KDC_ERR_REVOKED_CERTIFICATE", 

1983 73: "KDC_ERR_REVOCATION_STATUS_UNKNOWN", 

1984 74: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE", 

1985 75: "KDC_ERR_CLIENT_NAME_MISMATCH", 

1986 76: "KDC_ERR_KDC_NAME_MISMATCH", 

1987 # draft-ietf-kitten-iakerb 

1988 85: "KRB_AP_ERR_IAKERB_KDC_NOT_FOUND", 

1989 86: "KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE", 

1990 # RFC6113 

1991 90: "KDC_ERR_PREAUTH_EXPIRED", 

1992 91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED", 

1993 92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET", 

1994 93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS", 

1995 }, 

1996 explicit_tag=0xA6, 

1997 ), 

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

1999 ASN1F_optional( 

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

2001 ), 

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

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

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

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

2006 ), 

2007 implicit_tag=ASN1_Class_KRB.ERROR, 

2008 ) 

2009 

2010 def getSPN(self): 

2011 return "%s@%s" % ( 

2012 self.sname.toString(), 

2013 self.realm.val.decode(), 

2014 ) 

2015 

2016 

2017# PA-FX-ERROR 

2018_PADATA_CLASSES[137] = KRB_ERROR 

2019 

2020 

2021# [MS-KILE] sect 2.2.1 

2022 

2023 

2024class KERB_EXT_ERROR(Packet): 

2025 fields_desc = [ 

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

2027 XLEIntField("reserved", 0), 

2028 XLEIntField("flags", 0x00000001), 

2029 ] 

2030 

2031 

2032# [MS-KILE] sect 2.2.2 

2033 

2034 

2035class _Error_Field(ASN1F_STRING_PacketField): 

2036 def m2i(self, pkt, s): 

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

2038 if not val[0].val: 

2039 return val 

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

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

2042 return val 

2043 

2044 

2045class KERB_ERROR_DATA(ASN1_Packet): 

2046 ASN1_codec = ASN1_Codecs.BER 

2047 ASN1_root = ASN1F_SEQUENCE( 

2048 ASN1F_enum_INTEGER( 

2049 "dataType", 

2050 2, 

2051 { 

2052 1: "KERB_AP_ERR_TYPE_NTSTATUS", # from the wdk 

2053 2: "KERB_AP_ERR_TYPE_SKEW_RECOVERY", 

2054 3: "KERB_ERR_TYPE_EXTENDED", 

2055 }, 

2056 explicit_tag=0xA1, 

2057 ), 

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

2059 ) 

2060 

2061 

2062# This looks like an undocumented structure. 

2063 

2064 

2065class KERB_ERROR_UNK(ASN1_Packet): 

2066 ASN1_codec = ASN1_Codecs.BER 

2067 ASN1_root = ASN1F_SEQUENCE( 

2068 ASN1F_SEQUENCE( 

2069 ASN1F_enum_INTEGER( 

2070 "dataType", 

2071 0, 

2072 { 

2073 -128: "KDC_ERR_MUST_USE_USER2USER", 

2074 }, 

2075 explicit_tag=0xA0, 

2076 ), 

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

2078 ) 

2079 ) 

2080 

2081 

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

2083 

2084 

2085class KRB_TGT_REQ(ASN1_Packet): 

2086 ASN1_codec = ASN1_Codecs.BER 

2087 ASN1_root = ASN1F_SEQUENCE( 

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

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

2090 ASN1F_optional( 

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

2092 ), 

2093 ASN1F_optional( 

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

2095 ), 

2096 ) 

2097 

2098 

2099class KRB_TGT_REP(ASN1_Packet): 

2100 ASN1_codec = ASN1_Codecs.BER 

2101 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

2105 ) 

2106 

2107 

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

2109 

2110 

2111class KRB_FINISHED(ASN1_Packet): 

2112 ASN1_codec = ASN1_Codecs.BER 

2113 ASN1_root = ASN1F_SEQUENCE( 

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

2115 ) 

2116 

2117 

2118# RFC 6542 sect 3.1 

2119 

2120 

2121class KRB_GSS_EXT(Packet): 

2122 fields_desc = [ 

2123 IntEnumField( 

2124 "type", 

2125 0, 

2126 { 

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

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

2129 0x00000001: "GSS_EXTS_IAKERB_FINISHED", # not standard 

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

2131 }, 

2132 ), 

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

2134 MultipleTypeField( 

2135 [ 

2136 ( 

2137 PacketField("data", KRB_FINISHED(), KRB_FINISHED), 

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

2139 ), 

2140 ], 

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

2142 ), 

2143 ] 

2144 

2145 

2146# RFC 4121 sect 4.1.1 

2147 

2148 

2149class KRB_AuthenticatorChecksum(Packet): 

2150 fields_desc = [ 

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

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

2153 FlagsField( 

2154 "Flags", 

2155 0, 

2156 -32, 

2157 { 

2158 0x01: "GSS_C_DELEG_FLAG", 

2159 0x02: "GSS_C_MUTUAL_FLAG", 

2160 0x04: "GSS_C_REPLAY_FLAG", 

2161 0x08: "GSS_C_SEQUENCE_FLAG", 

2162 0x10: "GSS_C_CONF_FLAG", # confidentiality 

2163 0x20: "GSS_C_INTEG_FLAG", # integrity 

2164 # RFC4757 

2165 0x1000: "GSS_C_DCE_STYLE", 

2166 0x2000: "GSS_C_IDENTIFY_FLAG", 

2167 0x4000: "GSS_C_EXTENDED_ERROR_FLAG", 

2168 }, 

2169 ), 

2170 ConditionalField( 

2171 LEShortField("DlgOpt", 0), 

2172 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2173 ), 

2174 ConditionalField( 

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

2176 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2177 ), 

2178 ConditionalField( 

2179 PacketLenField( 

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

2181 ), 

2182 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2183 ), 

2184 # Extensions: RFC 6542 sect 3.1 

2185 PacketListField("Exts", KRB_GSS_EXT(), KRB_GSS_EXT), 

2186 ] 

2187 

2188 

2189# Kerberos V5 GSS-API - RFC1964 and RFC4121 

2190 

2191_TOK_IDS = { 

2192 # RFC 1964 

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

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

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

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

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

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

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

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

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

2202 # RFC 4121 

2203 b"\x04\x04": "GSS_GetMIC", 

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

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

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

2207} 

2208_SGN_ALGS = { 

2209 0x00: "DES MAC MD5", 

2210 0x01: "MD2.5", 

2211 0x02: "DES MAC", 

2212 # RFC 4757 

2213 0x11: "HMAC", 

2214} 

2215_SEAL_ALGS = { 

2216 0: "DES", 

2217 0xFFFF: "none", 

2218 # RFC 4757 

2219 0x10: "RC4", 

2220} 

2221 

2222 

2223# RFC 1964 - sect 1.1 

2224 

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

2226_InitialContextTokens = {} # filled below 

2227 

2228 

2229class KRB_InnerToken(Packet): 

2230 name = "Kerberos v5 InnerToken" 

2231 fields_desc = [ 

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

2233 PacketField( 

2234 "root", 

2235 KRB_AP_REQ(), 

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

2237 ), 

2238 ] 

2239 

2240 def mysummary(self): 

2241 return self.sprintf( 

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

2243 ) 

2244 

2245 def guess_payload_class(self, payload): 

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

2247 return conf.padding_layer 

2248 return Kerberos 

2249 

2250 @classmethod 

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

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

2253 # Older RFC1964 variants of the token have KRB_GSSAPI_Token wrapper 

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

2255 return KRB_GSSAPI_Token 

2256 return cls 

2257 

2258 

2259# RFC 4121 - sect 4.1 

2260 

2261 

2262class KRB_GSSAPI_Token(GSSAPI_BLOB): 

2263 name = "Kerberos GSSAPI-Token" 

2264 ASN1_codec = ASN1_Codecs.BER 

2265 ASN1_root = ASN1F_SEQUENCE( 

2266 ASN1F_OID("MechType", "1.2.840.113554.1.2.2"), 

2267 ASN1F_PACKET( 

2268 "innerToken", 

2269 KRB_InnerToken(), 

2270 KRB_InnerToken, 

2271 implicit_tag=0x0, 

2272 ), 

2273 implicit_tag=ASN1_Class_KRB.Token, 

2274 ) 

2275 

2276 

2277# RFC 1964 - sect 1.2.1 

2278 

2279 

2280class KRB_GSS_MIC_RFC1964(Packet): 

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

2282 fields_desc = [ 

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

2284 XLEIntField("Filler", 0xFFFFFFFF), 

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

2286 PadField( # sect 1.2.2.3 

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

2288 align=8, 

2289 padwith=b"\x04", 

2290 ), 

2291 ] 

2292 

2293 def default_payload_class(self, payload): 

2294 return conf.padding_layer 

2295 

2296 

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

2298 

2299# RFC 1964 - sect 1.2.2 

2300 

2301 

2302class KRB_GSS_Wrap_RFC1964(Packet): 

2303 name = "Kerberos v5 GSS_Wrap (RFC1964)" 

2304 fields_desc = [ 

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

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

2307 XLEShortField("Filler", 0xFFFF), 

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

2309 PadField( # sect 1.2.2.3 

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

2311 align=8, 

2312 padwith=b"\x04", 

2313 ), 

2314 # sect 1.2.2.3 

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

2316 ] 

2317 

2318 def default_payload_class(self, payload): 

2319 return conf.padding_layer 

2320 

2321 

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

2323 

2324 

2325# RFC 1964 - sect 1.2.2 

2326 

2327 

2328class KRB_GSS_Delete_sec_context_RFC1964(Packet): 

2329 name = "Kerberos v5 GSS_Delete_sec_context (RFC1964)" 

2330 fields_desc = KRB_GSS_MIC_RFC1964.fields_desc 

2331 

2332 

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

2334 

2335 

2336# RFC 4121 - sect 4.2.2 

2337_KRB5_GSS_Flags = [ 

2338 "SentByAcceptor", 

2339 "Sealed", 

2340 "AcceptorSubkey", 

2341] 

2342 

2343 

2344# RFC 4121 - sect 4.2.6.1 

2345 

2346 

2347class KRB_GSS_MIC(Packet): 

2348 name = "Kerberos v5 MIC Token" 

2349 fields_desc = [ 

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

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

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

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

2354 ] 

2355 

2356 def default_payload_class(self, payload): 

2357 return conf.padding_layer 

2358 

2359 

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

2361 

2362 

2363# RFC 4121 - sect 4.2.6.2 

2364 

2365 

2366class KRB_GSS_Wrap(Packet): 

2367 name = "Kerberos v5 Wrap Token" 

2368 fields_desc = [ 

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

2370 XByteField("Filler", 0xFF), 

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

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

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

2374 MultipleTypeField( 

2375 [ 

2376 ( 

2377 XStrField("Data", b""), 

2378 lambda pkt: pkt.Flags.Sealed, 

2379 ) 

2380 ], 

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

2382 ), 

2383 ] 

2384 

2385 def default_payload_class(self, payload): 

2386 return conf.padding_layer 

2387 

2388 

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

2390 

2391 

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

2393 

2394 

2395class IAKERB_HEADER(ASN1_Packet): 

2396 ASN1_codec = ASN1_Codecs.BER 

2397 ASN1_root = ASN1F_SEQUENCE( 

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

2399 ASN1F_optional( 

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

2401 ), 

2402 ) 

2403 

2404 

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

2406 

2407 

2408# Register for GSSAPI 

2409 

2410# Kerberos 5 

2411_GSSAPI_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2412_GSSAPI_SIGNATURE_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2413# Kerberos 5 - U2U 

2414_GSSAPI_OIDS["1.2.840.113554.1.2.2.3"] = KRB_InnerToken 

2415# Kerberos 5 - IAKERB 

2416_GSSAPI_OIDS["1.3.6.1.5.2.5"] = KRB_InnerToken 

2417 

2418 

2419# Entry class 

2420 

2421# RFC4120 sect 5.10 

2422 

2423 

2424class Kerberos(ASN1_Packet): 

2425 ASN1_codec = ASN1_Codecs.BER 

2426 ASN1_root = ASN1F_CHOICE( 

2427 "root", 

2428 None, 

2429 # RFC4120 

2430 KRB_GSSAPI_Token, # [APPLICATION 0] 

2431 KRB_Ticket, # [APPLICATION 1] 

2432 KRB_Authenticator, # [APPLICATION 2] 

2433 KRB_AS_REQ, # [APPLICATION 10] 

2434 KRB_AS_REP, # [APPLICATION 11] 

2435 KRB_TGS_REQ, # [APPLICATION 12] 

2436 KRB_TGS_REP, # [APPLICATION 13] 

2437 KRB_AP_REQ, # [APPLICATION 14] 

2438 KRB_AP_REP, # [APPLICATION 15] 

2439 # RFC4120 

2440 KRB_ERROR, # [APPLICATION 30] 

2441 ) 

2442 

2443 def mysummary(self): 

2444 return self.root.summary() 

2445 

2446 

2447bind_bottom_up(UDP, Kerberos, sport=88) 

2448bind_bottom_up(UDP, Kerberos, dport=88) 

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

2450 

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

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

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

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

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

2456 

2457 

2458# RFC4120 sect 7.2.2 

2459 

2460 

2461class KerberosTCPHeader(Packet): 

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

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

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

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

2466 

2467 @classmethod 

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

2469 if len(data) < 4: 

2470 return None 

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

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

2473 return cls(data) 

2474 

2475 

2476bind_layers(KerberosTCPHeader, Kerberos) 

2477 

2478bind_bottom_up(TCP, KerberosTCPHeader, sport=88) 

2479bind_layers(TCP, KerberosTCPHeader, dport=88) 

2480 

2481 

2482# RFC3244 sect 2 

2483 

2484 

2485class KPASSWD_REQ(Packet): 

2486 fields_desc = [ 

2487 ShortField("len", None), 

2488 ShortField("pvno", 0xFF80), 

2489 ShortField("apreqlen", None), 

2490 PacketLenField( 

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

2492 ), 

2493 ConditionalField( 

2494 PacketLenField( 

2495 "krbpriv", 

2496 KRB_PRIV(), 

2497 KRB_PRIV, 

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

2499 ), 

2500 lambda pkt: pkt.apreqlen != 0, 

2501 ), 

2502 ConditionalField( 

2503 PacketLenField( 

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

2505 ), 

2506 lambda pkt: pkt.apreqlen == 0, 

2507 ), 

2508 ] 

2509 

2510 def post_build(self, p, pay): 

2511 if self.len is None: 

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

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

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

2515 return p + pay 

2516 

2517 

2518class ChangePasswdData(ASN1_Packet): 

2519 ASN1_codec = ASN1_Codecs.BER 

2520 ASN1_root = ASN1F_SEQUENCE( 

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

2522 ASN1F_optional( 

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

2524 ), 

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

2526 ) 

2527 

2528 

2529class KPASSWD_REP(Packet): 

2530 fields_desc = [ 

2531 ShortField("len", None), 

2532 ShortField("pvno", 0x0001), 

2533 ShortField("apreplen", None), 

2534 PacketLenField( 

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

2536 ), 

2537 ConditionalField( 

2538 PacketLenField( 

2539 "krbpriv", 

2540 KRB_PRIV(), 

2541 KRB_PRIV, 

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

2543 ), 

2544 lambda pkt: pkt.apreplen != 0, 

2545 ), 

2546 ConditionalField( 

2547 PacketLenField( 

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

2549 ), 

2550 lambda pkt: pkt.apreplen == 0, 

2551 ), 

2552 ] 

2553 

2554 def post_build(self, p, pay): 

2555 if self.len is None: 

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

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

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

2559 return p + pay 

2560 

2561 def answers(self, other): 

2562 return isinstance(other, KPASSWD_REQ) 

2563 

2564 

2565KPASSWD_RESULTS = { 

2566 0: "KRB5_KPASSWD_SUCCESS", 

2567 1: "KRB5_KPASSWD_MALFORMED", 

2568 2: "KRB5_KPASSWD_HARDERROR", 

2569 3: "KRB5_KPASSWD_AUTHERROR", 

2570 4: "KRB5_KPASSWD_SOFTERROR", 

2571 5: "KRB5_KPASSWD_ACCESSDENIED", 

2572 6: "KRB5_KPASSWD_BAD_VERSION", 

2573 7: "KRB5_KPASSWD_INITIAL_FLAG_NEEDED", 

2574} 

2575 

2576 

2577class KPasswdRepData(Packet): 

2578 fields_desc = [ 

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

2580 StrField("resultString", ""), 

2581 ] 

2582 

2583 

2584class Kpasswd(Packet): 

2585 @classmethod 

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

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

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

2589 return KPASSWD_REQ 

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

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

2592 if asn1_tag == 14: 

2593 return KPASSWD_REQ 

2594 elif asn1_tag == 15: 

2595 return KPASSWD_REP 

2596 return KPASSWD_REQ 

2597 

2598 

2599bind_bottom_up(UDP, Kpasswd, sport=464) 

2600bind_bottom_up(UDP, Kpasswd, dport=464) 

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

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

2603 

2604 

2605class KpasswdTCPHeader(Packet): 

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

2607 

2608 @classmethod 

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

2610 if len(data) < 4: 

2611 return None 

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

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

2614 return cls(data) 

2615 

2616 

2617bind_layers(KpasswdTCPHeader, Kpasswd) 

2618 

2619bind_bottom_up(TCP, KpasswdTCPHeader, sport=464) 

2620bind_layers(TCP, KpasswdTCPHeader, dport=464) 

2621 

2622# [MS-KKDCP] 

2623 

2624 

2625class _KerbMessage_Field(ASN1F_STRING_PacketField): 

2626 def m2i(self, pkt, s): 

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

2628 if not val[0].val: 

2629 return val 

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

2631 

2632 

2633class KDC_PROXY_MESSAGE(ASN1_Packet): 

2634 ASN1_codec = ASN1_Codecs.BER 

2635 ASN1_root = ASN1F_SEQUENCE( 

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

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

2638 ASN1F_optional( 

2639 ASN1F_FLAGS( 

2640 "dclocatorHint", 

2641 None, 

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

2643 explicit_tag=0xA2, 

2644 ) 

2645 ), 

2646 ) 

2647 

2648 

2649class KdcProxySocket(SuperSocket): 

2650 """ 

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

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

2653 """ 

2654 

2655 def __init__( 

2656 self, 

2657 url, 

2658 targetDomain, 

2659 dclocatorHint=None, 

2660 no_check_certificate=False, 

2661 **kwargs, 

2662 ): 

2663 self.url = url 

2664 self.targetDomain = targetDomain 

2665 self.dclocatorHint = dclocatorHint 

2666 self.no_check_certificate = no_check_certificate 

2667 self.queue = deque() 

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

2669 

2670 def recv(self, x=None): 

2671 return self.queue.popleft() 

2672 

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

2674 from scapy.layers.http import HTTP_Client 

2675 

2676 cli = HTTP_Client(no_check_certificate=self.no_check_certificate) 

2677 try: 

2678 # sr it via the web client 

2679 resp = cli.request( 

2680 self.url, 

2681 Method="POST", 

2682 data=bytes( 

2683 # Wrap request in KDC_PROXY_MESSAGE 

2684 KDC_PROXY_MESSAGE( 

2685 kerbMessage=bytes(x), 

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

2687 # dclocatorHint is optional 

2688 dclocatorHint=self.dclocatorHint, 

2689 ) 

2690 ), 

2691 http_headers={ 

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

2693 "Pragma": "no-cache", 

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

2695 }, 

2696 ) 

2697 if resp and conf.raw_layer in resp: 

2698 # Parse the payload 

2699 resp = KDC_PROXY_MESSAGE(resp.load).kerbMessage 

2700 # We have an answer, queue it. 

2701 self.queue.append(resp) 

2702 else: 

2703 raise EOFError 

2704 finally: 

2705 cli.close() 

2706 

2707 @staticmethod 

2708 def select(sockets, remain=None): 

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

2710 

2711 

2712# Util functions 

2713 

2714 

2715class KerberosClient(Automaton): 

2716 """ 

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

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

2719 :param upn: the UPN of the client. 

2720 :param password: the password of the client. 

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

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

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

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

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

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

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

2728 :param u2u: sets the U2U flag 

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

2730 :param s4u2proxy: sets the S4U2Proxy flag 

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

2732 :param kdc_proxy: specify a KDC proxy url 

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

2734 :param fast: use FAST armoring 

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

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

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

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

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

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

2741 """ 

2742 

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

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

2745 

2746 class MODE(IntEnum): 

2747 AS_REQ = 0 

2748 TGS_REQ = 1 

2749 GET_SALT = 2 

2750 

2751 def __init__( 

2752 self, 

2753 mode=MODE.AS_REQ, 

2754 ip=None, 

2755 upn=None, 

2756 password=None, 

2757 key=None, 

2758 realm=None, 

2759 spn=None, 

2760 ticket=None, 

2761 host=None, 

2762 renew=False, 

2763 additional_tickets=[], 

2764 u2u=False, 

2765 for_user=None, 

2766 s4u2proxy=False, 

2767 dmsa=False, 

2768 kdc_proxy=None, 

2769 kdc_proxy_no_check_certificate=False, 

2770 fast=False, 

2771 armor_ticket=None, 

2772 armor_ticket_upn=None, 

2773 armor_ticket_skey=None, 

2774 key_list_req=[], 

2775 etypes=None, 

2776 port=88, 

2777 timeout=5, 

2778 **kwargs, 

2779 ): 

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

2781 from scapy.layers.ldap import dclocator 

2782 

2783 if not upn: 

2784 raise ValueError("Invalid upn") 

2785 if not spn: 

2786 raise ValueError("Invalid spn") 

2787 if realm is None: 

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

2789 _, realm = _parse_upn(upn) 

2790 elif mode == self.MODE.TGS_REQ: 

2791 _, realm = _parse_spn(spn) 

2792 if not realm and ticket: 

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

2794 # of the ticket. 

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

2796 else: 

2797 raise ValueError("Invalid realm") 

2798 

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

2800 if not host: 

2801 raise ValueError("Invalid host") 

2802 elif mode == self.MODE.TGS_REQ: 

2803 if not ticket: 

2804 raise ValueError("Invalid ticket") 

2805 

2806 if not ip and not kdc_proxy: 

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

2808 ip = dclocator( 

2809 realm, 

2810 timeout=timeout, 

2811 # Use connect mode instead of ldap for compatibility 

2812 # with MIT kerberos servers 

2813 mode="connect", 

2814 port=port, 

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

2816 ).ip 

2817 

2818 if fast: 

2819 if mode == self.MODE.AS_REQ: 

2820 # Requires an external ticket 

2821 if not armor_ticket or not armor_ticket_upn or not armor_ticket_skey: 

2822 raise ValueError( 

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

2824 "please provide the 3 required armor arguments" 

2825 ) 

2826 elif mode == self.MODE.TGS_REQ: 

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

2828 raise ValueError( 

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

2830 ) 

2831 

2832 if mode == self.MODE.GET_SALT: 

2833 if etypes is not None: 

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

2835 

2836 from scapy.libs.rfc3961 import EncryptionType 

2837 

2838 etypes = [ 

2839 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

2840 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

2841 ] 

2842 elif etypes is None: 

2843 from scapy.libs.rfc3961 import EncryptionType 

2844 

2845 etypes = [ 

2846 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

2847 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

2848 EncryptionType.RC4_HMAC, 

2849 EncryptionType.RC4_HMAC_EXP, 

2850 EncryptionType.DES_CBC_MD5, 

2851 ] 

2852 self.etypes = etypes 

2853 

2854 self.mode = mode 

2855 

2856 self.result = None # Result 

2857 

2858 self._timeout = timeout 

2859 self._ip = ip 

2860 self._port = port 

2861 self.kdc_proxy = kdc_proxy 

2862 self.kdc_proxy_no_check_certificate = kdc_proxy_no_check_certificate 

2863 

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

2865 self.host = host.upper() 

2866 self.password = password and bytes_encode(password) 

2867 self.spn = spn 

2868 self.upn = upn 

2869 self.realm = realm.upper() 

2870 self.ticket = ticket 

2871 self.fast = fast 

2872 self.armor_ticket = armor_ticket 

2873 self.armor_ticket_upn = armor_ticket_upn 

2874 self.armor_ticket_skey = armor_ticket_skey 

2875 self.key_list_req = key_list_req 

2876 self.renew = renew 

2877 self.additional_tickets = additional_tickets # U2U + S4U2Proxy 

2878 self.u2u = u2u # U2U 

2879 self.for_user = for_user # FOR-USER 

2880 self.s4u2proxy = s4u2proxy # S4U2Proxy 

2881 self.dmsa = dmsa # DMSA 

2882 self.key = key 

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

2884 self.replykey = None # Key used for reply 

2885 # See RFC4120 - sect 7.2.2 

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

2887 self.should_followup = False 

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

2889 self.fast_req_sent = False 

2890 # Session parameters 

2891 self.pre_auth = False 

2892 self.fast_rep = None 

2893 self.fast_error = None 

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

2895 self.fast_armorkey = None # The armor key 

2896 self.fxcookie = None 

2897 

2898 sock = self._connect() 

2899 super(KerberosClient, self).__init__( 

2900 sock=sock, 

2901 **kwargs, 

2902 ) 

2903 

2904 def _connect(self): 

2905 if self.kdc_proxy: 

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

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

2908 sock = KdcProxySocket( 

2909 url=self.kdc_proxy, 

2910 targetDomain=self.realm, 

2911 no_check_certificate=self.kdc_proxy_no_check_certificate, 

2912 ) 

2913 else: 

2914 sock = socket.socket() 

2915 sock.settimeout(self._timeout) 

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

2917 sock = StreamSocket(sock, KerberosTCPHeader) 

2918 return sock 

2919 

2920 def send(self, pkt): 

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

2922 

2923 def _base_kdc_req(self, now_time): 

2924 kdcreq = KRB_KDC_REQ_BODY( 

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

2926 additionalTickets=None, 

2927 # Windows default 

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

2929 cname=None, 

2930 realm=ASN1_GENERAL_STRING(self.realm), 

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

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

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

2934 ) 

2935 if self.renew: 

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

2937 return kdcreq 

2938 

2939 def calc_fast_armorkey(self): 

2940 """ 

2941 Calculate and return the FAST armorkey 

2942 """ 

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

2944 from scapy.libs.rfc3961 import Key, KRB_FX_CF2 

2945 

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

2947 # AS-REQ mode 

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

2949 

2950 self.fast_armorkey = KRB_FX_CF2( 

2951 self.fast_skey, 

2952 self.armor_ticket_skey, 

2953 b"subkeyarmor", 

2954 b"ticketarmor", 

2955 ) 

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

2957 # TGS-REQ: 2 cases 

2958 

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

2960 

2961 if not self.armor_ticket: 

2962 # Case 1: Implicit armoring 

2963 self.fast_armorkey = KRB_FX_CF2( 

2964 self.subkey, 

2965 self.key, 

2966 b"subkeyarmor", 

2967 b"ticketarmor", 

2968 ) 

2969 else: 

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

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

2972 

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

2974 

2975 explicit_armor_key = KRB_FX_CF2( 

2976 self.fast_skey, 

2977 self.armor_ticket_skey, 

2978 b"subkeyarmor", 

2979 b"ticketarmor", 

2980 ) 

2981 

2982 self.fast_armorkey = KRB_FX_CF2( 

2983 explicit_armor_key, 

2984 self.subkey, 

2985 b"explicitarmor", 

2986 b"tgsarmor", 

2987 ) 

2988 

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

2990 """ 

2991 :param kdc_req: the KDC_REQ_BODY to wrap 

2992 :param padata: the list of PADATA to wrap 

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

2994 """ 

2995 

2996 # Create the PA Fast request wrapper 

2997 pafastreq = PA_FX_FAST_REQUEST( 

2998 armoredData=KrbFastArmoredReq( 

2999 reqChecksum=Checksum(), 

3000 encFastReq=EncryptedData(), 

3001 ) 

3002 ) 

3003 

3004 if self.armor_ticket is not None: 

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

3006 

3007 pafastreq.armoredData.armor = KrbFastArmor( 

3008 armorType=1, # FX_FAST_ARMOR_AP_REQUEST 

3009 armorValue=KRB_AP_REQ( 

3010 ticket=self.armor_ticket, 

3011 authenticator=EncryptedData(), 

3012 ), 

3013 ) 

3014 

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

3016 _, crealm = _parse_upn(self.armor_ticket_upn) 

3017 authenticator = KRB_Authenticator( 

3018 crealm=ASN1_GENERAL_STRING(crealm), 

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

3020 cksum=None, 

3021 ctime=ASN1_GENERALIZED_TIME(now_time), 

3022 cusec=ASN1_INTEGER(0), 

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

3024 seqNumber=ASN1_INTEGER(0), 

3025 encAuthorizationData=None, 

3026 ) 

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

3028 self.armor_ticket_skey, 

3029 authenticator, 

3030 ) 

3031 

3032 # Sign the fast request wrapper 

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

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

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

3036 pafastreq.armoredData.reqChecksum.make( 

3037 self.fast_armorkey, 

3038 bytes(pa_tgsreq_ap), 

3039 ) 

3040 else: 

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

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

3043 # containing message" 

3044 pafastreq.armoredData.reqChecksum.make( 

3045 self.fast_armorkey, 

3046 bytes(kdc_req), 

3047 ) 

3048 

3049 # Build and encrypt the Fast request 

3050 fastreq = KrbFastReq( 

3051 padata=padata, 

3052 reqBody=kdc_req, 

3053 ) 

3054 pafastreq.armoredData.encFastReq.encrypt( 

3055 self.fast_armorkey, 

3056 fastreq, 

3057 ) 

3058 

3059 # Return the PADATA 

3060 return PADATA( 

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

3062 padataValue=pafastreq, 

3063 ) 

3064 

3065 def as_req(self): 

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

3067 

3068 # 1. Build and populate KDC-REQ 

3069 kdc_req = self._base_kdc_req(now_time=now_time) 

3070 kdc_req.addresses = [ 

3071 HostAddress( 

3072 addrType=ASN1_INTEGER(20), # Netbios 

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

3074 ) 

3075 ] 

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

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

3078 

3079 # 2. Build the list of PADATA 

3080 padata = [ 

3081 PADATA( 

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

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

3084 ) 

3085 ] 

3086 

3087 # Cookie support 

3088 if self.fxcookie: 

3089 padata.insert( 

3090 0, 

3091 PADATA( 

3092 padataType=133, # PA-FX-COOKIE 

3093 padataValue=self.fxcookie, 

3094 ), 

3095 ) 

3096 

3097 # FAST 

3098 if self.fast: 

3099 # Calculate the armor key 

3100 self.calc_fast_armorkey() 

3101 

3102 # [MS-KILE] sect 3.2.5.5 

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

3104 padata.append( 

3105 PADATA( 

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

3107 padataValue=PA_PAC_OPTIONS( 

3108 options="Claims", 

3109 ), 

3110 ) 

3111 ) 

3112 

3113 # Pre-auth is requested 

3114 if self.pre_auth: 

3115 if self.fast: 

3116 # Special FAST factor 

3117 # RFC6113 sect 5.4.6 

3118 from scapy.libs.rfc3961 import KRB_FX_CF2 

3119 

3120 # Calculate the 'challenge key' 

3121 ts_key = KRB_FX_CF2( 

3122 self.fast_armorkey, 

3123 self.key, 

3124 b"clientchallengearmor", 

3125 b"challengelongterm", 

3126 ) 

3127 pafactor = PADATA( 

3128 padataType=138, # PA-ENCRYPTED-CHALLENGE 

3129 padataValue=EncryptedData(), 

3130 ) 

3131 else: 

3132 # Usual 'timestamp' factor 

3133 ts_key = self.key 

3134 pafactor = PADATA( 

3135 padataType=2, # PA-ENC-TIMESTAMP 

3136 padataValue=EncryptedData(), 

3137 ) 

3138 pafactor.padataValue.encrypt( 

3139 ts_key, 

3140 PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), 

3141 ) 

3142 padata.insert( 

3143 0, 

3144 pafactor, 

3145 ) 

3146 

3147 # FAST support 

3148 if self.fast: 

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

3150 # hidden inside the encrypted section. 

3151 padata = [ 

3152 self._fast_wrap( 

3153 kdc_req=kdc_req, 

3154 padata=padata, 

3155 now_time=now_time, 

3156 ) 

3157 ] 

3158 

3159 # 3. Build the request 

3160 asreq = Kerberos( 

3161 root=KRB_AS_REQ( 

3162 padata=padata, 

3163 reqBody=kdc_req, 

3164 ) 

3165 ) 

3166 

3167 # Note the reply key 

3168 self.replykey = self.key 

3169 

3170 return asreq 

3171 

3172 def tgs_req(self): 

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

3174 

3175 # Compute armor key for FAST 

3176 if self.fast: 

3177 self.calc_fast_armorkey() 

3178 

3179 # 1. Build and populate KDC-REQ 

3180 kdc_req = self._base_kdc_req(now_time=now_time) 

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

3182 

3183 # Additional tickets 

3184 if self.additional_tickets: 

3185 kdc_req.additionalTickets = self.additional_tickets 

3186 

3187 # U2U 

3188 if self.u2u: 

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

3190 

3191 # 2. Build the list of PADATA 

3192 padata = [] 

3193 

3194 # [MS-SFU] FOR-USER extension 

3195 if self.for_user is not None: 

3196 from scapy.libs.rfc3961 import ChecksumType, EncryptionType 

3197 

3198 # [MS-SFU] note 4: 

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

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

3201 # certificate is available. 

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

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

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

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

3206 

3207 # 1. Add PA_S4U_X509_USER 

3208 pasfux509 = PA_S4U_X509_USER( 

3209 userId=S4UUserID( 

3210 nonce=kdc_req.nonce, 

3211 # [MS-SFU] note 5: 

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

3213 options="USE_REPLY_KEY_USAGE", 

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

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

3216 subjectCertificate=None, # TODO 

3217 ), 

3218 checksum=Checksum(), 

3219 ) 

3220 

3221 if self.dmsa: 

3222 # DMSA = set UNCONDITIONAL_DELEGATION to 1 

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

3224 

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

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

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

3228 pasfux509.checksum.make( 

3229 self.key, 

3230 bytes(pasfux509.userId), 

3231 cksumtype=ChecksumType.RSA_MD4, 

3232 ) 

3233 else: 

3234 pasfux509.checksum.make( 

3235 self.key, 

3236 bytes(pasfux509.userId), 

3237 ) 

3238 padata.append( 

3239 PADATA( 

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

3241 padataValue=pasfux509, 

3242 ) 

3243 ) 

3244 

3245 # 2. Add PA_FOR_USER 

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

3247 paforuser = PA_FOR_USER( 

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

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

3250 cksum=Checksum(), 

3251 ) 

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

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

3254 ) + ( 

3255 ( 

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

3257 + paforuser.userRealm.val 

3258 + paforuser.authPackage.val 

3259 ).encode() 

3260 ) 

3261 paforuser.cksum.make( 

3262 self.key, 

3263 S4UByteArray, 

3264 cksumtype=ChecksumType.HMAC_MD5, 

3265 ) 

3266 padata.append( 

3267 PADATA( 

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

3269 padataValue=paforuser, 

3270 ) 

3271 ) 

3272 

3273 # [MS-SFU] S4U2proxy - sect 3.1.5.2.1 

3274 if self.s4u2proxy: 

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

3276 padata.append( 

3277 PADATA( 

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

3279 padataValue=PA_PAC_OPTIONS( 

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

3281 ), 

3282 ) 

3283 ) 

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

3285 kdc_req.kdcOptions.set(14, 1) 

3286 

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

3288 if self.key_list_req: 

3289 padata.append( 

3290 PADATA( 

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

3292 padataValue=KERB_KEY_LIST_REQ( 

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

3294 ), 

3295 ) 

3296 ) 

3297 

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

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

3300 pa_tgs_req = PADATA( 

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

3302 padataValue=apreq, 

3303 ) 

3304 

3305 # 4. Populate it's authenticator 

3306 _, crealm = _parse_upn(self.upn) 

3307 authenticator = KRB_Authenticator( 

3308 crealm=ASN1_GENERAL_STRING(crealm), 

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

3310 cksum=None, 

3311 ctime=ASN1_GENERALIZED_TIME(now_time), 

3312 cusec=ASN1_INTEGER(0), 

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

3314 seqNumber=None, 

3315 encAuthorizationData=None, 

3316 ) 

3317 

3318 # Compute checksum 

3319 if self.key.cksumtype: 

3320 authenticator.cksum = Checksum() 

3321 authenticator.cksum.make( 

3322 self.key, 

3323 bytes(kdc_req), 

3324 ) 

3325 

3326 # Encrypt authenticator 

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

3328 

3329 # 5. Process FAST if required 

3330 if self.fast: 

3331 padata = [ 

3332 self._fast_wrap( 

3333 kdc_req=kdc_req, 

3334 padata=padata, 

3335 now_time=now_time, 

3336 pa_tgsreq_ap=apreq, 

3337 ) 

3338 ] 

3339 

3340 # 6. Add the final PADATA 

3341 padata.append(pa_tgs_req) 

3342 

3343 # 7. Build the request 

3344 tgsreq = Kerberos( 

3345 root=KRB_TGS_REQ( 

3346 padata=padata, 

3347 reqBody=kdc_req, 

3348 ) 

3349 ) 

3350 

3351 # Note the reply key 

3352 if self.subkey: 

3353 self.replykey = self.subkey 

3354 else: 

3355 self.replykey = self.key 

3356 

3357 return tgsreq 

3358 

3359 @ATMT.state(initial=1) 

3360 def BEGIN(self): 

3361 pass 

3362 

3363 @ATMT.condition(BEGIN) 

3364 def should_send_as_req(self): 

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

3366 raise self.SENT_AS_REQ() 

3367 

3368 @ATMT.condition(BEGIN) 

3369 def should_send_tgs_req(self): 

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

3371 raise self.SENT_TGS_REQ() 

3372 

3373 @ATMT.action(should_send_as_req) 

3374 def send_as_req(self): 

3375 self.send(self.as_req()) 

3376 

3377 @ATMT.action(should_send_tgs_req) 

3378 def send_tgs_req(self): 

3379 self.send(self.tgs_req()) 

3380 

3381 @ATMT.state() 

3382 def SENT_AS_REQ(self): 

3383 pass 

3384 

3385 @ATMT.state() 

3386 def SENT_TGS_REQ(self): 

3387 pass 

3388 

3389 def _process_padatas_and_key(self, padatas): 

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

3391 

3392 etype = None 

3393 salt = b"" 

3394 # 1. Process pa-data 

3395 if padatas is not None: 

3396 for padata in padatas: 

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

3398 elt = padata.padataValue.seq[0] 

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

3400 etype = elt.etype.val 

3401 if etype != EncryptionType.RC4_HMAC: 

3402 salt = elt.salt.val 

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

3404 self.fxcookie = padata.padataValue 

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

3406 if isinstance(padata.padataValue, PA_FX_FAST_REPLY): 

3407 self.fast_rep = ( 

3408 padata.padataValue.armoredData.encFastRep.decrypt( 

3409 self.fast_armorkey, 

3410 ) 

3411 ) 

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

3413 self.fast_error = padata.padataValue 

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

3415 # Verify S4U checksum 

3416 key_usage_number = None 

3417 pasfux509 = padata.padataValue 

3418 # [MS-SFU] sect 2.2.2 

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

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

3421 key_usage_number = 27 

3422 pasfux509.checksum.verify( 

3423 self.key, 

3424 bytes(pasfux509.userId), 

3425 key_usage_number=key_usage_number, 

3426 ) 

3427 

3428 # 2. Update the current key if necessary 

3429 

3430 # Compute key if not already provided 

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

3432 self.key = Key.string_to_key( 

3433 etype, 

3434 self.password, 

3435 salt, 

3436 ) 

3437 

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

3439 if self.fast_rep and self.fast_rep.strengthenKey: 

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

3441 self.replykey = KRB_FX_CF2( 

3442 self.fast_rep.strengthenKey.toKey(), 

3443 self.replykey, 

3444 b"strengthenkey", 

3445 b"replykey", 

3446 ) 

3447 

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

3449 def receive_salt_mode(self, pkt): 

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

3451 # exit. 

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

3453 if Kerberos not in pkt: 

3454 raise self.FINAL() 

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

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

3457 raise self.FINAL() 

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

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

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

3461 elt = padata.padataValue.seq[0] 

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

3463 self.result = elt.salt.val 

3464 raise self.FINAL() 

3465 else: 

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

3467 raise self.FINAL() 

3468 

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

3470 def receive_krb_error_as_req(self, pkt): 

3471 # We check for Kerberos errors. 

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

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

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

3475 # Process PAs if available 

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

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

3478 

3479 # Special case for FAST errors 

3480 if self.fast_rep: 

3481 # This is actually a fast response error ! 

3482 frep, self.fast_rep = self.fast_rep, None 

3483 # Re-process PAs 

3484 self._process_padatas_and_key(frep.padata) 

3485 # Extract real Kerberos error from FAST message 

3486 ferr = Kerberos(root=self.fast_error) 

3487 self.fast_error = None 

3488 # Recurse 

3489 self.receive_krb_error_as_req(ferr) 

3490 return 

3491 

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

3493 if not self.key: 

3494 log_runtime.error( 

3495 "Got 'KDC_ERR_PREAUTH_REQUIRED', " 

3496 "but no possible key could be computed." 

3497 ) 

3498 raise self.FINAL() 

3499 self.should_followup = True 

3500 self.pre_auth = True 

3501 raise self.BEGIN() 

3502 else: 

3503 log_runtime.error("Received KRB_ERROR") 

3504 pkt.show() 

3505 raise self.FINAL() 

3506 

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

3508 def receive_as_rep(self, pkt): 

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

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

3511 

3512 @ATMT.eof(SENT_AS_REQ) 

3513 def retry_after_eof_in_apreq(self): 

3514 if self.should_followup: 

3515 # Reconnect and Restart 

3516 self.should_followup = False 

3517 self.update_sock(self._connect()) 

3518 raise self.BEGIN() 

3519 else: 

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

3521 raise self.FINAL() 

3522 

3523 @ATMT.action(receive_as_rep) 

3524 def decrypt_as_rep(self, pkt): 

3525 self._process_padatas_and_key(pkt.root.padata) 

3526 if not self.pre_auth: 

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

3528 

3529 # Process FAST response 

3530 if self.fast_rep: 

3531 # Verify the ticket-checksum 

3532 self.fast_rep.finished.ticketChecksum.verify( 

3533 self.fast_armorkey, 

3534 bytes(pkt.root.ticket), 

3535 ) 

3536 self.fast_rep = None 

3537 elif self.fast: 

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

3539 

3540 # Decrypt AS-REP response 

3541 enc = pkt.root.encPart 

3542 res = enc.decrypt(self.replykey) 

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

3544 

3545 @ATMT.receive_condition(SENT_TGS_REQ) 

3546 def receive_krb_error_tgs_req(self, pkt): 

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

3548 # Process PAs if available 

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

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

3551 

3552 if self.fast_rep: 

3553 # This is actually a fast response error ! 

3554 frep, self.fast_rep = self.fast_rep, None 

3555 # Re-process PAs 

3556 self._process_padatas_and_key(frep.padata) 

3557 # Extract real Kerberos error from FAST message 

3558 ferr = Kerberos(root=self.fast_error) 

3559 self.fast_error = None 

3560 # Recurse 

3561 self.receive_krb_error_tgs_req(ferr) 

3562 return 

3563 

3564 if ( 

3565 pkt.root.errorCode == 0x07 

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

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

3568 ): 

3569 log_runtime.warning( 

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

3571 ) 

3572 else: 

3573 log_runtime.warning("Received KRB_ERROR") 

3574 pkt.show() 

3575 raise self.FINAL() 

3576 

3577 @ATMT.receive_condition(SENT_TGS_REQ) 

3578 def receive_tgs_rep(self, pkt): 

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

3580 if ( 

3581 not self.renew 

3582 and not self.dmsa 

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

3584 ): 

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

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

3587 

3588 @ATMT.action(receive_tgs_rep) 

3589 def decrypt_tgs_rep(self, pkt): 

3590 self._process_padatas_and_key(pkt.root.padata) 

3591 

3592 # Process FAST response 

3593 if self.fast_rep: 

3594 # Verify the ticket-checksum 

3595 self.fast_rep.finished.ticketChecksum.verify( 

3596 self.fast_armorkey, 

3597 bytes(pkt.root.ticket), 

3598 ) 

3599 self.fast_rep = None 

3600 elif self.fast: 

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

3602 

3603 # Decrypt TGS-REP response 

3604 enc = pkt.root.encPart 

3605 if self.subkey: 

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

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

3608 # authenticator subkey is used." 

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

3610 else: 

3611 res = enc.decrypt(self.replykey) 

3612 

3613 # Store result 

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

3615 

3616 @ATMT.state(final=1) 

3617 def FINAL(self): 

3618 pass 

3619 

3620 

3621def _parse_upn(upn): 

3622 """ 

3623 Extract the username and realm from full UPN 

3624 """ 

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

3626 if not m: 

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

3628 if "/" in upn: 

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

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

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

3632 raise ValueError(err) 

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

3634 user = m.group(1) 

3635 domain = m.group(3) 

3636 else: 

3637 user = m.group(3) 

3638 domain = m.group(1) 

3639 return user, domain 

3640 

3641 

3642def _parse_spn(spn): 

3643 """ 

3644 Extract ServiceName and realm from full SPN 

3645 """ 

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

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

3648 if not m: 

3649 try: 

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

3651 return _parse_upn(spn) 

3652 except ValueError: 

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

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

3655 

3656 

3657def _spn_are_equal(spn1, spn2): 

3658 """ 

3659 Check that two SPNs are equal. 

3660 """ 

3661 spn1, _ = _parse_spn(spn1) 

3662 spn2, _ = _parse_spn(spn2) 

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

3664 

3665 

3666def krb_as_req( 

3667 upn, spn=None, ip=None, key=None, password=None, realm=None, host="WIN10", **kwargs 

3668): 

3669 r""" 

3670 Kerberos AS-Req 

3671 

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

3673 or "user@DOMAIN" 

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

3675 Defaults to "krbtgt/<realm>" 

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

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

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

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

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

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

3682 

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

3684 

3685 Example:: 

3686 

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

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

3689 

3690 Equivalent:: 

3691 

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

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

3694 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

3696 """ 

3697 if realm is None: 

3698 _, realm = _parse_upn(upn) 

3699 if key is None: 

3700 if password is None: 

3701 try: 

3702 from prompt_toolkit import prompt 

3703 

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

3705 except ImportError: 

3706 password = input("Enter password: ") 

3707 cli = KerberosClient( 

3708 mode=KerberosClient.MODE.AS_REQ, 

3709 realm=realm, 

3710 ip=ip, 

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

3712 host=host, 

3713 upn=upn, 

3714 password=password, 

3715 key=key, 

3716 **kwargs, 

3717 ) 

3718 cli.run() 

3719 cli.stop() 

3720 return cli.result 

3721 

3722 

3723def krb_tgs_req( 

3724 upn, 

3725 spn, 

3726 sessionkey, 

3727 ticket, 

3728 ip=None, 

3729 renew=False, 

3730 realm=None, 

3731 additional_tickets=[], 

3732 u2u=False, 

3733 etypes=None, 

3734 for_user=None, 

3735 s4u2proxy=False, 

3736 **kwargs, 

3737): 

3738 r""" 

3739 Kerberos TGS-Req 

3740 

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

3742 or "user@DOMAIN" 

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

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

3745 :param ticket: the tgt ticket 

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

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

3748 :param renew: ask for renewal 

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

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

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

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

3753 :param etypes: array of EncryptionType values. 

3754 By default: AES128, AES256, RC4, DES_MD5 

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

3756 S4U2Self extension. 

3757 

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

3759 

3760 Example:: 

3761 

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

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

3764 

3765 Equivalent:: 

3766 

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

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

3769 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

3771 """ 

3772 cli = KerberosClient( 

3773 mode=KerberosClient.MODE.TGS_REQ, 

3774 realm=realm, 

3775 upn=upn, 

3776 ip=ip, 

3777 spn=spn, 

3778 key=sessionkey, 

3779 ticket=ticket, 

3780 renew=renew, 

3781 additional_tickets=additional_tickets, 

3782 u2u=u2u, 

3783 etypes=etypes, 

3784 for_user=for_user, 

3785 s4u2proxy=s4u2proxy, 

3786 **kwargs, 

3787 ) 

3788 cli.run() 

3789 cli.stop() 

3790 return cli.result 

3791 

3792 

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

3794 """ 

3795 Kerberos AS-Req then TGS-Req 

3796 """ 

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

3798 if not res: 

3799 return 

3800 return krb_tgs_req( 

3801 upn=upn, 

3802 spn=spn, 

3803 sessionkey=res.sessionkey, 

3804 ticket=res.asrep.ticket, 

3805 ip=ip, 

3806 **kwargs, 

3807 ) 

3808 

3809 

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

3811 """ 

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

3813 """ 

3814 if realm is None: 

3815 _, realm = _parse_upn(upn) 

3816 cli = KerberosClient( 

3817 mode=KerberosClient.MODE.GET_SALT, 

3818 realm=realm, 

3819 ip=ip, 

3820 spn="krbtgt/" + realm, 

3821 upn=upn, 

3822 host=host, 

3823 **kwargs, 

3824 ) 

3825 cli.run() 

3826 cli.stop() 

3827 return cli.result 

3828 

3829 

3830def kpasswd( 

3831 upn, 

3832 targetupn=None, 

3833 ip=None, 

3834 password=None, 

3835 newpassword=None, 

3836 key=None, 

3837 ticket=None, 

3838 realm=None, 

3839 ssp=None, 

3840 setpassword=None, 

3841 timeout=3, 

3842 port=464, 

3843 debug=0, 

3844 **kwargs, 

3845): 

3846 """ 

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

3848 

3849 :param upn: the UPN to use for authentication 

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

3851 same as upn. 

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

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

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

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

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

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

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

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

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

3861 """ 

3862 from scapy.layers.ldap import dclocator 

3863 

3864 if not realm: 

3865 _, realm = _parse_upn(upn) 

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

3867 if ip is None: 

3868 ip = dclocator( 

3869 realm, 

3870 timeout=timeout, 

3871 # Use connect mode instead of ldap for compatibility 

3872 # with MIT kerberos servers 

3873 mode="connect", 

3874 port=port, 

3875 debug=debug, 

3876 ).ip 

3877 if ssp is None and ticket is not None: 

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

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

3880 if tktspn == "krbtgt": 

3881 log_runtime.info( 

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

3883 ) 

3884 setpassword = True 

3885 resp = krb_tgs_req( 

3886 upn=upn, 

3887 spn=spn, 

3888 ticket=ticket, 

3889 sessionkey=key, 

3890 ip=ip, 

3891 debug=debug, 

3892 ) 

3893 if resp is None: 

3894 return 

3895 ticket = resp.tgsrep.ticket 

3896 key = resp.sessionkey 

3897 if setpassword is None: 

3898 setpassword = bool(targetupn) 

3899 elif setpassword and targetupn is None: 

3900 targetupn = upn 

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

3902 # Get a ticket for kadmin/changepw 

3903 if ssp is None: 

3904 if ticket is None: 

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

3906 resp = krb_as_req( 

3907 upn=upn, 

3908 spn=spn, 

3909 key=key, 

3910 ip=ip, 

3911 password=password, 

3912 debug=debug, 

3913 ) 

3914 if resp is None: 

3915 return 

3916 ticket = resp.asrep.ticket 

3917 key = resp.sessionkey 

3918 ssp = KerberosSSP( 

3919 UPN=upn, 

3920 SPN=spn, 

3921 ST=ticket, 

3922 KEY=key, 

3923 DC_IP=ip, 

3924 debug=debug, 

3925 **kwargs, 

3926 ) 

3927 Context, tok, negResult = ssp.GSS_Init_sec_context( 

3928 None, 

3929 req_flags=0, # No GSS_C_MUTUAL_FLAG 

3930 ) 

3931 if negResult != GSS_S_CONTINUE_NEEDED: 

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

3933 if tok: 

3934 tok.show() 

3935 return 

3936 apreq = tok.innerToken.root 

3937 # Connect 

3938 sock = socket.socket() 

3939 sock.settimeout(timeout) 

3940 sock.connect((ip, port)) 

3941 sock = StreamSocket(sock, KpasswdTCPHeader) 

3942 # Do KPASSWD request 

3943 if newpassword is None: 

3944 try: 

3945 from prompt_toolkit import prompt 

3946 

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

3948 except ImportError: 

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

3950 krbpriv = KRB_PRIV(encPart=EncryptedData()) 

3951 krbpriv.encPart.encrypt( 

3952 Context.KrbSessionKey, 

3953 EncKrbPrivPart( 

3954 sAddress=HostAddress( 

3955 addrType=ASN1_INTEGER(2), # IPv4 

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

3957 ), 

3958 userData=ASN1_STRING( 

3959 bytes( 

3960 ChangePasswdData( 

3961 newpasswd=newpassword, 

3962 targname=PrincipalName.fromUPN(targetupn), 

3963 targrealm=realm, 

3964 ) 

3965 ) 

3966 if setpassword 

3967 else newpassword 

3968 ), 

3969 timestamp=None, 

3970 usec=None, 

3971 seqNumber=Context.SendSeqNum, 

3972 ), 

3973 ) 

3974 resp = sock.sr1( 

3975 KpasswdTCPHeader() 

3976 / KPASSWD_REQ( 

3977 pvno=0xFF80 if setpassword else 1, 

3978 apreq=apreq, 

3979 krbpriv=krbpriv, 

3980 ), 

3981 timeout=timeout, 

3982 verbose=0, 

3983 ) 

3984 # Verify KPASSWD response 

3985 if not resp: 

3986 raise TimeoutError("KPASSWD_REQ timed out !") 

3987 if KPASSWD_REP not in resp: 

3988 resp.show() 

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

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

3991 if negResult != GSS_S_COMPLETE: 

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

3993 if tok: 

3994 tok.show() 

3995 return 

3996 # Parse answer KRB_PRIV 

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

3998 userRep = KPasswdRepData(krbanswer.userData.val) 

3999 if userRep.resultCode != 0: 

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

4001 userRep.show() 

4002 return 

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

4004 

4005 

4006# SSP 

4007 

4008 

4009class KerberosSSP(SSP): 

4010 """ 

4011 The KerberosSSP 

4012 

4013 Client settings: 

4014 

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

4016 If not provided, will be retrieved 

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

4018 target_name provided in the GSS_Init_sec_context 

4019 :param UPN: The client UPN 

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

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

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

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

4024 OR the session key associated with the TGT 

4025 OR the kerberos key associated with the UPN 

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

4027 password of the UPN. 

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

4029 

4030 Server settings: 

4031 

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

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

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

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

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

4037 this IP using using the KEY when using U2U. 

4038 """ 

4039 

4040 oid = "1.2.840.113554.1.2.2" 

4041 auth_type = 0x10 

4042 

4043 class STATE(SSP.STATE): 

4044 INIT = 1 

4045 CLI_SENT_TGTREQ = 2 

4046 CLI_SENT_APREQ = 3 

4047 CLI_RCVD_APREP = 4 

4048 SRV_SENT_APREP = 5 

4049 FAILED = -1 

4050 

4051 class CONTEXT(SSP.CONTEXT): 

4052 __slots__ = [ 

4053 "SessionKey", 

4054 "ServerHostname", 

4055 "U2U", 

4056 "KrbSessionKey", # raw Key object 

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

4058 "SeqNum", # for AP 

4059 "SendSeqNum", # for MIC 

4060 "RecvSeqNum", # for MIC 

4061 "IsAcceptor", 

4062 "SendSealKeyUsage", 

4063 "SendSignKeyUsage", 

4064 "RecvSealKeyUsage", 

4065 "RecvSignKeyUsage", 

4066 # server-only 

4067 "UPN", 

4068 "PAC", 

4069 ] 

4070 

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

4072 self.state = KerberosSSP.STATE.INIT 

4073 self.SessionKey = None 

4074 self.ServerHostname = None 

4075 self.U2U = False 

4076 self.SendSeqNum = 0 

4077 self.RecvSeqNum = 0 

4078 self.KrbSessionKey = None 

4079 self.STSessionKey = None 

4080 self.IsAcceptor = IsAcceptor 

4081 self.UPN = None 

4082 self.PAC = None 

4083 # [RFC 4121] sect 2 

4084 if IsAcceptor: 

4085 self.SendSealKeyUsage = 22 

4086 self.SendSignKeyUsage = 23 

4087 self.RecvSealKeyUsage = 24 

4088 self.RecvSignKeyUsage = 25 

4089 else: 

4090 self.SendSealKeyUsage = 24 

4091 self.SendSignKeyUsage = 25 

4092 self.RecvSealKeyUsage = 22 

4093 self.RecvSignKeyUsage = 23 

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

4095 

4096 def clifailure(self): 

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

4098 

4099 def __repr__(self): 

4100 if self.U2U: 

4101 return "KerberosSSP-U2U" 

4102 return "KerberosSSP" 

4103 

4104 def __init__( 

4105 self, 

4106 ST=None, 

4107 UPN=None, 

4108 PASSWORD=None, 

4109 U2U=False, 

4110 KEY=None, 

4111 SPN=None, 

4112 TGT=None, 

4113 DC_IP=None, 

4114 SKEY_TYPE=None, 

4115 debug=0, 

4116 **kwargs, 

4117 ): 

4118 self.ST = ST 

4119 self.UPN = UPN 

4120 self.KEY = KEY 

4121 self.SPN = SPN 

4122 self.TGT = TGT 

4123 self.PASSWORD = PASSWORD 

4124 self.U2U = U2U 

4125 self.DC_IP = DC_IP 

4126 self.debug = debug 

4127 if SKEY_TYPE is None: 

4128 from scapy.libs.rfc3961 import EncryptionType 

4129 

4130 SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96 

4131 self.SKEY_TYPE = SKEY_TYPE 

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

4133 

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

4135 """ 

4136 [MS-KILE] sect 3.4.5.6 

4137 

4138 - AES: RFC4121 sect 4.2.6.1 

4139 """ 

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

4141 # Concatenate the ToSign 

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

4143 sig = KRB_InnerToken( 

4144 TOK_ID=b"\x04\x04", 

4145 root=KRB_GSS_MIC( 

4146 Flags="AcceptorSubkey" 

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

4148 SND_SEQ=Context.SendSeqNum, 

4149 ), 

4150 ) 

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

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

4153 keyusage=Context.SendSignKeyUsage, 

4154 text=ToSign, 

4155 ) 

4156 else: 

4157 raise NotImplementedError 

4158 Context.SendSeqNum += 1 

4159 return sig 

4160 

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

4162 """ 

4163 [MS-KILE] sect 3.4.5.7 

4164 

4165 - AES: RFC4121 sect 4.2.6.1 

4166 """ 

4167 Context.RecvSeqNum = signature.root.SND_SEQ 

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

4169 # Concatenate the ToSign 

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

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

4172 sig = Context.KrbSessionKey.make_checksum( 

4173 keyusage=Context.RecvSignKeyUsage, 

4174 text=ToSign, 

4175 ) 

4176 else: 

4177 raise NotImplementedError 

4178 if sig != signature.root.SGN_CKSUM: 

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

4180 

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

4182 """ 

4183 [MS-KILE] sect 3.4.5.4 

4184 

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

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

4187 """ 

4188 # Is confidentiality in use? 

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

4190 x.conf_req_flag for x in msgs 

4191 ) 

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

4193 # Build token 

4194 tok = KRB_InnerToken( 

4195 TOK_ID=b"\x05\x04", 

4196 root=KRB_GSS_Wrap( 

4197 Flags="AcceptorSubkey" 

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

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

4200 SND_SEQ=Context.SendSeqNum, 

4201 RRC=0, 

4202 ), 

4203 ) 

4204 Context.SendSeqNum += 1 

4205 # Real separation starts now: RFC4121 sect 4.2.4 

4206 if confidentiality: 

4207 # Confidentiality is requested (see RFC4121 sect 4.3) 

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

4209 # 0. Roll confounder 

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

4211 # 1. Concatenate the data to be encrypted 

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

4213 DataLen = len(Data) 

4214 # 2. Add filler 

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

4216 # be zero" 

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

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

4219 Data += Filler 

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

4221 PlainHeader = bytes(tok)[:16] 

4222 Data += PlainHeader 

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

4224 ToSign = Confounder 

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

4226 ToSign += Filler 

4227 ToSign += PlainHeader 

4228 # 5. Finalize token for signing 

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

4230 tok.root.RRC = 28 

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

4232 # integrity protection) 

4233 Data = Context.KrbSessionKey.encrypt( 

4234 keyusage=Context.SendSealKeyUsage, 

4235 plaintext=Data, 

4236 confounder=Confounder, 

4237 signtext=ToSign, 

4238 ) 

4239 # 7. Rotate 

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

4241 # 8. Split (token and encrypted messages) 

4242 toklen = len(Data) - DataLen 

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

4244 offset = toklen 

4245 for msg in msgs: 

4246 msglen = len(msg.data) 

4247 if msg.conf_req_flag: 

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

4249 offset += msglen 

4250 return msgs, tok 

4251 else: 

4252 # No confidentiality is requested 

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

4254 # 0. Concatenate the data 

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

4256 DataLen = len(Data) 

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

4258 ToSign = Data 

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

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

4261 # checksum mechanism 

4262 Mic = Context.KrbSessionKey.make_checksum( 

4263 keyusage=Context.SendSealKeyUsage, 

4264 text=ToSign, 

4265 ) 

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

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

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

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

4270 # is requested" 

4271 tok.root.RRC = 12 

4272 # 3. Concat and pack 

4273 for msg in msgs: 

4274 if msg.sign: 

4275 msg.data = b"" 

4276 Data = Data + Mic 

4277 # 4. Rotate 

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

4279 return msgs, tok 

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

4281 from scapy.libs.rfc3961 import ( 

4282 Cipher, 

4283 Hmac_MD5, 

4284 _rfc1964pad, 

4285 decrepit_algorithms, 

4286 ) 

4287 

4288 # Build token 

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

4290 tok = KRB_InnerToken( 

4291 TOK_ID=b"\x02\x01", 

4292 root=KRB_GSS_Wrap_RFC1964( 

4293 SGN_ALG="HMAC", 

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

4295 SND_SEQ=seq 

4296 + ( 

4297 # See errata 

4298 b"\xff\xff\xff\xff" 

4299 if Context.IsAcceptor 

4300 else b"\x00\x00\x00\x00" 

4301 ), 

4302 ), 

4303 ) 

4304 Context.SendSeqNum += 1 

4305 # 0. Concatenate data 

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

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

4308 Kss = Context.KrbSessionKey.key 

4309 # 1. Roll confounder 

4310 Confounder = os.urandom(8) 

4311 # 2. Compute the 'Kseq' key 

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

4313 if Context.KrbSessionKey.etype == 24: # EXP 

4314 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4315 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

4316 else: 

4317 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

4318 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

4319 # 3. Build SGN_CKSUM 

4320 tok.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

4321 keyusage=13, # See errata 

4322 text=bytes(tok)[:8] + Confounder + ToSign, 

4323 )[:8] 

4324 # 4. Populate token + encrypt 

4325 if confidentiality: 

4326 # 'encrypt' is requested 

4327 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

4328 tok.root.CONFOUNDER = rc4.update(Confounder) 

4329 Data = rc4.update(ToEncrypt) 

4330 # Split encrypted data 

4331 offset = 0 

4332 for msg in msgs: 

4333 msglen = len(msg.data) 

4334 if msg.conf_req_flag: 

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

4336 offset += msglen 

4337 else: 

4338 # 'encrypt' is not requested 

4339 tok.root.CONFOUNDER = Confounder 

4340 # 5. Compute the 'Kseq' key 

4341 if Context.KrbSessionKey.etype == 24: # EXP 

4342 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4343 Kseq = Kseq[:7] + b"\xab" * 9 

4344 else: 

4345 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

4346 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

4347 # 6. Encrypt 'SND_SEQ' 

4348 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

4349 tok.root.SND_SEQ = rc4.update(tok.root.SND_SEQ) 

4350 # 7. Include 'InitialContextToken pseudo ASN.1 header' 

4351 tok = KRB_GSSAPI_Token( 

4352 MechType="1.2.840.113554.1.2.2", # Kerberos 5 

4353 innerToken=tok, 

4354 ) 

4355 return msgs, tok 

4356 else: 

4357 raise NotImplementedError 

4358 

4359 def GSS_UnwrapEx(self, Context, msgs, signature): 

4360 """ 

4361 [MS-KILE] sect 3.4.5.5 

4362 

4363 - AES: RFC4121 sect 4.2.6.2 

4364 - HMAC-RC4: RFC4757 sect 7.3 

4365 """ 

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

4367 confidentiality = signature.root.Flags.Sealed 

4368 # Real separation starts now: RFC4121 sect 4.2.4 

4369 if confidentiality: 

4370 # 0. Concatenate the data 

4371 Data = signature.root.Data 

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

4373 # 1. Un-Rotate 

4374 Data = strrot(Data, signature.root.RRC + signature.root.EC, right=False) 

4375 

4376 # 2. Function to build 'ToSign', exclusively used for checksum 

4377 def MakeToSign(Confounder, DecText): 

4378 offset = 0 

4379 # 2.a Confounder 

4380 ToSign = Confounder 

4381 # 2.b Messages 

4382 for msg in msgs: 

4383 msglen = len(msg.data) 

4384 if msg.conf_req_flag: 

4385 ToSign += DecText[offset : offset + msglen] 

4386 offset += msglen 

4387 elif msg.sign: 

4388 ToSign += msg.data 

4389 # 2.c Filler & Padding 

4390 ToSign += DecText[offset:] 

4391 return ToSign 

4392 

4393 # 3. Decrypt 

4394 Data = Context.KrbSessionKey.decrypt( 

4395 keyusage=Context.RecvSealKeyUsage, 

4396 ciphertext=Data, 

4397 presignfunc=MakeToSign, 

4398 ) 

4399 # 4. Split 

4400 Data, f16header = ( 

4401 Data[:-16], 

4402 Data[-16:], 

4403 ) 

4404 # 5. Check header 

4405 hdr = signature.copy() 

4406 hdr.root.RRC = 0 

4407 if f16header != bytes(hdr)[:16]: 

4408 raise ValueError("ERROR: Headers don't match") 

4409 # 6. Split (and ignore filler) 

4410 offset = 0 

4411 for msg in msgs: 

4412 msglen = len(msg.data) 

4413 if msg.conf_req_flag: 

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

4415 offset += msglen 

4416 # Case without msgs 

4417 if len(msgs) == 1 and not msgs[0].data: 

4418 msgs[0].data = Data 

4419 return msgs 

4420 else: 

4421 # No confidentiality is requested 

4422 # 0. Concatenate the data 

4423 Data = signature.root.Data 

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

4425 # 1. Un-Rotate 

4426 Data = strrot(Data, signature.root.RRC, right=False) 

4427 # 2. Split 

4428 Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :] 

4429 # "Both the EC field and the RRC field in 

4430 # the token header SHALL be filled with zeroes for the purpose of 

4431 # calculating the checksum." 

4432 ToSign = Data 

4433 hdr = signature.copy() 

4434 hdr.root.RRC = 0 

4435 hdr.root.EC = 0 

4436 # Concatenate the data 

4437 ToSign += bytes(hdr)[:16] 

4438 # 3. Calculate the signature 

4439 sig = Context.KrbSessionKey.make_checksum( 

4440 keyusage=Context.RecvSealKeyUsage, 

4441 text=ToSign, 

4442 ) 

4443 # 4. Compare 

4444 if sig != Mic: 

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

4446 # Case without msgs 

4447 if len(msgs) == 1 and not msgs[0].data: 

4448 msgs[0].data = Data 

4449 return msgs 

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

4451 from scapy.libs.rfc3961 import ( 

4452 Cipher, 

4453 Hmac_MD5, 

4454 _rfc1964pad, 

4455 decrepit_algorithms, 

4456 ) 

4457 

4458 # Drop wrapping 

4459 tok = signature.innerToken 

4460 

4461 # Detect confidentiality 

4462 confidentiality = tok.root.SEAL_ALG != 0xFFFF 

4463 

4464 # 0. Concatenate data 

4465 ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

4466 Kss = Context.KrbSessionKey.key 

4467 # 1. Compute the 'Kseq' key 

4468 if Context.KrbSessionKey.etype == 24: # EXP 

4469 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4470 Kseq = Kseq[:7] + b"\xab" * 9 

4471 else: 

4472 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

4473 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

4474 # 2. Decrypt 'SND_SEQ' 

4475 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

4476 seq = rc4.update(tok.root.SND_SEQ)[:4] 

4477 # 3. Compute the 'Kcrypt' key 

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

4479 if Context.KrbSessionKey.etype == 24: # EXP 

4480 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4481 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

4482 else: 

4483 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

4484 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

4485 # 4. Decrypt 

4486 if confidentiality: 

4487 # 'encrypt' was requested 

4488 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

4489 Confounder = rc4.update(tok.root.CONFOUNDER) 

4490 Data = rc4.update(ToDecrypt) 

4491 # Split encrypted data 

4492 offset = 0 

4493 for msg in msgs: 

4494 msglen = len(msg.data) 

4495 if msg.conf_req_flag: 

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

4497 offset += msglen 

4498 else: 

4499 # 'encrypt' was not requested 

4500 Confounder = tok.root.CONFOUNDER 

4501 # 5. Verify SGN_CKSUM 

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

4503 Context.KrbSessionKey.verify_checksum( 

4504 keyusage=13, # See errata 

4505 text=bytes(tok)[:8] + Confounder + ToSign, 

4506 cksum=tok.root.SGN_CKSUM, 

4507 ) 

4508 return msgs 

4509 else: 

4510 raise NotImplementedError 

4511 

4512 def GSS_Init_sec_context( 

4513 self, 

4514 Context: CONTEXT, 

4515 token=None, 

4516 target_name: Optional[str] = None, 

4517 req_flags: Optional[GSS_C_FLAGS] = None, 

4518 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

4519 ): 

4520 if Context is None: 

4521 # New context 

4522 Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags) 

4523 

4524 from scapy.libs.rfc3961 import Key 

4525 

4526 if Context.state == self.STATE.INIT and self.U2U: 

4527 # U2U - Get TGT 

4528 Context.state = self.STATE.CLI_SENT_TGTREQ 

4529 return ( 

4530 Context, 

4531 KRB_GSSAPI_Token( 

4532 MechType="1.2.840.113554.1.2.2.3", # U2U 

4533 innerToken=KRB_InnerToken( 

4534 TOK_ID=b"\x04\x00", 

4535 root=KRB_TGT_REQ(), 

4536 ), 

4537 ), 

4538 GSS_S_CONTINUE_NEEDED, 

4539 ) 

4540 

4541 if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]: 

4542 if not self.UPN: 

4543 raise ValueError("Missing UPN attribute") 

4544 # Do we have a ST? 

4545 if self.ST is None: 

4546 # Client sends an AP-req 

4547 if not self.SPN and not target_name: 

4548 raise ValueError("Missing SPN/target_name attribute") 

4549 additional_tickets = [] 

4550 if self.U2U: 

4551 try: 

4552 # GSSAPI / Kerberos 

4553 tgt_rep = token.root.innerToken.root 

4554 except AttributeError: 

4555 try: 

4556 # Kerberos 

4557 tgt_rep = token.innerToken.root 

4558 except AttributeError: 

4559 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4560 if not isinstance(tgt_rep, KRB_TGT_REP): 

4561 tgt_rep.show() 

4562 raise ValueError("KerberosSSP: Unexpected token !") 

4563 additional_tickets = [tgt_rep.ticket] 

4564 if self.TGT is not None: 

4565 if not self.KEY: 

4566 raise ValueError("Cannot use TGT without the KEY") 

4567 # Use TGT 

4568 res = krb_tgs_req( 

4569 upn=self.UPN, 

4570 spn=self.SPN or target_name, 

4571 ip=self.DC_IP, 

4572 sessionkey=self.KEY, 

4573 ticket=self.TGT, 

4574 additional_tickets=additional_tickets, 

4575 u2u=self.U2U, 

4576 debug=self.debug, 

4577 ) 

4578 else: 

4579 # Ask for TGT then ST 

4580 res = krb_as_and_tgs( 

4581 upn=self.UPN, 

4582 spn=self.SPN or target_name, 

4583 ip=self.DC_IP, 

4584 key=self.KEY, 

4585 password=self.PASSWORD, 

4586 additional_tickets=additional_tickets, 

4587 u2u=self.U2U, 

4588 debug=self.debug, 

4589 ) 

4590 if not res: 

4591 # Failed to retrieve the ticket 

4592 return Context, None, GSS_S_FAILURE 

4593 self.ST, self.KEY = res.tgsrep.ticket, res.sessionkey 

4594 elif not self.KEY: 

4595 raise ValueError("Must provide KEY with ST") 

4596 Context.STSessionKey = self.KEY 

4597 

4598 # Save ServerHostname 

4599 if len(self.ST.sname.nameString) == 2: 

4600 Context.ServerHostname = self.ST.sname.nameString[1].val.decode() 

4601 

4602 # Build the KRB-AP 

4603 apOptions = ASN1_BIT_STRING("000") 

4604 if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG: 

4605 apOptions.set(2, "1") # mutual-required 

4606 if self.U2U: 

4607 apOptions.set(1, "1") # use-session-key 

4608 Context.U2U = True 

4609 ap_req = KRB_AP_REQ( 

4610 apOptions=apOptions, 

4611 ticket=self.ST, 

4612 authenticator=EncryptedData(), 

4613 ) 

4614 

4615 # Get the current time 

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

4617 # Pick a random session key 

4618 Context.KrbSessionKey = Key.new_random_key( 

4619 self.SKEY_TYPE, 

4620 ) 

4621 

4622 # We use a random SendSeqNum 

4623 Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix() 

4624 

4625 # Get the realm of the client 

4626 _, crealm = _parse_upn(self.UPN) 

4627 

4628 # Build and encrypt the full KRB_Authenticator 

4629 ap_req.authenticator.encrypt( 

4630 Context.STSessionKey, 

4631 KRB_Authenticator( 

4632 crealm=crealm, 

4633 cname=PrincipalName.fromUPN(self.UPN), 

4634 # RFC 4121 checksum 

4635 cksum=Checksum( 

4636 cksumtype="KRB-AUTHENTICATOR", 

4637 checksum=KRB_AuthenticatorChecksum( 

4638 # RFC 4121 sect 4.1.1.2 

4639 # "The Bnd field contains the MD5 hash of channel bindings" 

4640 Bnd=( 

4641 chan_bindings.digestMD5() 

4642 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4643 else (b"\x00" * 16) 

4644 ), 

4645 Flags=int(Context.flags), 

4646 ), 

4647 ), 

4648 ctime=ASN1_GENERALIZED_TIME(now_time), 

4649 cusec=ASN1_INTEGER(0), 

4650 subkey=EncryptionKey.fromKey(Context.KrbSessionKey), 

4651 seqNumber=Context.SendSeqNum, 

4652 encAuthorizationData=AuthorizationData( 

4653 seq=[ 

4654 AuthorizationDataItem( 

4655 adType="AD-IF-RELEVANT", 

4656 adData=AuthorizationData( 

4657 seq=[ 

4658 AuthorizationDataItem( 

4659 adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

4660 adData=KERB_AD_RESTRICTION_ENTRY( 

4661 restriction=LSAP_TOKEN_INFO_INTEGRITY( 

4662 MachineID=bytes(RandBin(32)) 

4663 ) 

4664 ), 

4665 ), 

4666 # This isn't documented, but sent on Windows :/ 

4667 AuthorizationDataItem( 

4668 adType="KERB-LOCAL", 

4669 adData=b"\x00" * 16, 

4670 ), 

4671 ] 

4672 + ( 

4673 # Channel bindings 

4674 [ 

4675 AuthorizationDataItem( 

4676 adType="AD-AUTH-DATA-AP-OPTIONS", 

4677 adData=KERB_AUTH_DATA_AP_OPTIONS( 

4678 apOptions="KERB_AP_OPTIONS_CBT" 

4679 ), 

4680 ) 

4681 ] 

4682 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4683 else [] 

4684 ) 

4685 ), 

4686 ) 

4687 ] 

4688 ), 

4689 ), 

4690 ) 

4691 Context.state = self.STATE.CLI_SENT_APREQ 

4692 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

4693 # Raw kerberos DCE-STYLE 

4694 return Context, ap_req, GSS_S_CONTINUE_NEEDED 

4695 else: 

4696 # Kerberos wrapper 

4697 return ( 

4698 Context, 

4699 KRB_GSSAPI_Token( 

4700 innerToken=KRB_InnerToken( 

4701 root=ap_req, 

4702 ) 

4703 ), 

4704 GSS_S_CONTINUE_NEEDED, 

4705 ) 

4706 

4707 elif Context.state == self.STATE.CLI_SENT_APREQ: 

4708 if isinstance(token, KRB_AP_REP): 

4709 # Raw AP_REP was passed 

4710 ap_rep = token 

4711 else: 

4712 try: 

4713 # GSSAPI / Kerberos 

4714 ap_rep = token.root.innerToken.root 

4715 except AttributeError: 

4716 try: 

4717 # Kerberos 

4718 ap_rep = token.innerToken.root 

4719 except AttributeError: 

4720 try: 

4721 # Raw kerberos DCE-STYLE 

4722 ap_rep = token.root 

4723 except AttributeError: 

4724 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4725 if not isinstance(ap_rep, KRB_AP_REP): 

4726 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4727 # Retrieve SessionKey 

4728 repPart = ap_rep.encPart.decrypt(Context.STSessionKey) 

4729 if repPart.subkey is not None: 

4730 Context.SessionKey = repPart.subkey.keyvalue.val 

4731 Context.KrbSessionKey = repPart.subkey.toKey() 

4732 # OK ! 

4733 Context.state = self.STATE.CLI_RCVD_APREP 

4734 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

4735 # [MS-KILE] sect 3.4.5.1 

4736 # The client MUST generate an additional AP exchange reply message 

4737 # exactly as the server would as the final message to send to the 

4738 # server. 

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

4740 cli_ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

4741 cli_ap_rep.encPart.encrypt( 

4742 Context.STSessionKey, 

4743 EncAPRepPart( 

4744 ctime=ASN1_GENERALIZED_TIME(now_time), 

4745 seqNumber=repPart.seqNumber, 

4746 subkey=None, 

4747 ), 

4748 ) 

4749 return Context, cli_ap_rep, GSS_S_COMPLETE 

4750 return Context, None, GSS_S_COMPLETE 

4751 elif ( 

4752 Context.state == self.STATE.CLI_RCVD_APREP 

4753 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

4754 ): 

4755 # DCE_STYLE with SPNEGOSSP 

4756 return Context, None, GSS_S_COMPLETE 

4757 else: 

4758 raise ValueError("KerberosSSP: Unknown state") 

4759 

4760 def GSS_Accept_sec_context( 

4761 self, 

4762 Context: CONTEXT, 

4763 token=None, 

4764 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

4765 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

4766 ): 

4767 if Context is None: 

4768 # New context 

4769 Context = self.CONTEXT(IsAcceptor=True, req_flags=req_flags) 

4770 

4771 from scapy.libs.rfc3961 import Key 

4772 import scapy.layers.msrpce.mspac # noqa: F401 

4773 

4774 if Context.state == self.STATE.INIT: 

4775 if self.UPN and self.SPN: 

4776 raise ValueError("Cannot use SPN and UPN at the same time !") 

4777 if self.SPN and self.TGT: 

4778 raise ValueError("Cannot use TGT with SPN.") 

4779 if self.UPN and not self.TGT: 

4780 # UPN is provided: use U2U 

4781 res = krb_as_req( 

4782 self.UPN, 

4783 self.DC_IP, 

4784 key=self.KEY, 

4785 password=self.PASSWORD, 

4786 ) 

4787 self.TGT, self.KEY = res.asrep.ticket, res.sessionkey 

4788 

4789 # Server receives AP-req, sends AP-rep 

4790 if isinstance(token, KRB_AP_REQ): 

4791 # Raw AP_REQ was passed 

4792 ap_req = token 

4793 else: 

4794 try: 

4795 # GSSAPI/Kerberos 

4796 ap_req = token.root.innerToken.root 

4797 except AttributeError: 

4798 try: 

4799 # Kerberos 

4800 ap_req = token.innerToken.root 

4801 except AttributeError: 

4802 try: 

4803 # Raw kerberos 

4804 ap_req = token.root 

4805 except AttributeError: 

4806 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4807 

4808 if isinstance(ap_req, KRB_TGT_REQ): 

4809 # Special U2U case 

4810 Context.U2U = True 

4811 return ( 

4812 None, 

4813 KRB_GSSAPI_Token( 

4814 MechType="1.2.840.113554.1.2.2.3", # U2U 

4815 innerToken=KRB_InnerToken( 

4816 TOK_ID=b"\x04\x01", 

4817 root=KRB_TGT_REP( 

4818 ticket=self.TGT, 

4819 ), 

4820 ), 

4821 ), 

4822 GSS_S_CONTINUE_NEEDED, 

4823 ) 

4824 elif not isinstance(ap_req, KRB_AP_REQ): 

4825 ap_req.show() 

4826 raise ValueError("Unexpected type in KerberosSSP") 

4827 if not self.KEY: 

4828 raise ValueError("Missing KEY attribute") 

4829 

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

4831 

4832 # If using a UPN, require U2U 

4833 if self.UPN and ap_req.apOptions.val[1] != "1": # use-session-key 

4834 # Required but not provided. Return an error 

4835 Context.U2U = True 

4836 err = KRB_GSSAPI_Token( 

4837 innerToken=KRB_InnerToken( 

4838 TOK_ID=b"\x03\x00", 

4839 root=KRB_ERROR( 

4840 errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED", 

4841 stime=ASN1_GENERALIZED_TIME(now_time), 

4842 realm=ap_req.ticket.realm, 

4843 sname=ap_req.ticket.sname, 

4844 eData=KRB_TGT_REP( 

4845 ticket=self.TGT, 

4846 ), 

4847 ), 

4848 ) 

4849 ) 

4850 return Context, err, GSS_S_CONTINUE_NEEDED 

4851 

4852 # Validate the 'serverName' of the ticket. 

4853 sname = ap_req.ticket.getSPN() 

4854 our_sname = self.SPN or self.UPN 

4855 if not _spn_are_equal(our_sname, sname): 

4856 warning("KerberosSSP: bad server name: %s != %s" % (sname, our_sname)) 

4857 err = KRB_GSSAPI_Token( 

4858 innerToken=KRB_InnerToken( 

4859 TOK_ID=b"\x03\x00", 

4860 root=KRB_ERROR( 

4861 errorCode="KRB_AP_ERR_BADMATCH", 

4862 stime=ASN1_GENERALIZED_TIME(now_time), 

4863 realm=ap_req.ticket.realm, 

4864 sname=ap_req.ticket.sname, 

4865 eData=None, 

4866 ), 

4867 ) 

4868 ) 

4869 return Context, err, GSS_S_BAD_MECH 

4870 

4871 # Decrypt the ticket 

4872 try: 

4873 tkt = ap_req.ticket.encPart.decrypt(self.KEY) 

4874 except ValueError as ex: 

4875 warning("KerberosSSP: %s (bad KEY?)" % ex) 

4876 err = KRB_GSSAPI_Token( 

4877 innerToken=KRB_InnerToken( 

4878 TOK_ID=b"\x03\x00", 

4879 root=KRB_ERROR( 

4880 errorCode="KRB_AP_ERR_MODIFIED", 

4881 stime=ASN1_GENERALIZED_TIME(now_time), 

4882 realm=ap_req.ticket.realm, 

4883 sname=ap_req.ticket.sname, 

4884 eData=None, 

4885 ), 

4886 ) 

4887 ) 

4888 return Context, err, GSS_S_DEFECTIVE_TOKEN 

4889 

4890 # Store information about the user in the Context 

4891 if tkt.authorizationData and tkt.authorizationData.seq: 

4892 # Get AD-IF-RELEVANT 

4893 adIfRelevant = tkt.authorizationData.getAuthData(0x1) 

4894 if adIfRelevant: 

4895 # Get AD-WIN2K-PAC 

4896 Context.PAC = adIfRelevant.getAuthData(0x80) 

4897 

4898 # Get AP-REQ session key 

4899 Context.STSessionKey = tkt.key.toKey() 

4900 authenticator = ap_req.authenticator.decrypt(Context.STSessionKey) 

4901 

4902 # Compute an application session key ([MS-KILE] sect 3.1.1.2) 

4903 subkey = None 

4904 if ap_req.apOptions.val[2] == "1": # mutual-required 

4905 appkey = Key.new_random_key( 

4906 self.SKEY_TYPE, 

4907 ) 

4908 Context.KrbSessionKey = appkey 

4909 Context.SessionKey = appkey.key 

4910 subkey = EncryptionKey.fromKey(appkey) 

4911 else: 

4912 Context.KrbSessionKey = self.KEY 

4913 Context.SessionKey = self.KEY.key 

4914 

4915 # Eventually process the "checksum" 

4916 if authenticator.cksum and authenticator.cksum.cksumtype == 0x8003: 

4917 # KRB-Authenticator 

4918 authcksum = authenticator.cksum.checksum 

4919 Context.flags = authcksum.Flags 

4920 # Check channel bindings 

4921 if ( 

4922 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4923 and chan_bindings.digestMD5() != authcksum.Bnd 

4924 and not ( 

4925 GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS in req_flags 

4926 and authcksum.Bnd == GSS_C_NO_CHANNEL_BINDINGS 

4927 ) 

4928 ): 

4929 # Channel binding checks failed. 

4930 return Context, None, GSS_S_BAD_BINDINGS 

4931 elif ( 

4932 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

4933 and GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS not in req_flags 

4934 ): 

4935 # Uhoh, we required channel bindings 

4936 return Context, None, GSS_S_BAD_BINDINGS 

4937 

4938 # Build response (RFC4120 sect 3.2.4) 

4939 ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

4940 ap_rep.encPart.encrypt( 

4941 Context.STSessionKey, 

4942 EncAPRepPart( 

4943 ctime=authenticator.ctime, 

4944 cusec=authenticator.cusec, 

4945 seqNumber=None, 

4946 subkey=subkey, 

4947 ), 

4948 ) 

4949 Context.state = self.STATE.SRV_SENT_APREP 

4950 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

4951 # [MS-KILE] sect 3.4.5.1 

4952 return Context, ap_rep, GSS_S_CONTINUE_NEEDED 

4953 return Context, ap_rep, GSS_S_COMPLETE # success 

4954 elif ( 

4955 Context.state == self.STATE.SRV_SENT_APREP 

4956 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

4957 ): 

4958 # [MS-KILE] sect 3.4.5.1 

4959 # The server MUST receive the additional AP exchange reply message and 

4960 # verify that the message is constructed correctly. 

4961 if not token: 

4962 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4963 # Server receives AP-req, sends AP-rep 

4964 if isinstance(token, KRB_AP_REP): 

4965 # Raw AP_REP was passed 

4966 ap_rep = token 

4967 else: 

4968 try: 

4969 # GSSAPI/Kerberos 

4970 ap_rep = token.root.innerToken.root 

4971 except AttributeError: 

4972 try: 

4973 # Raw Kerberos 

4974 ap_rep = token.root 

4975 except AttributeError: 

4976 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4977 # Decrypt the AP-REP 

4978 try: 

4979 ap_rep.encPart.decrypt(Context.STSessionKey) 

4980 except ValueError as ex: 

4981 warning("KerberosSSP: %s (bad KEY?)" % ex) 

4982 return Context, None, GSS_S_DEFECTIVE_TOKEN 

4983 return Context, None, GSS_S_COMPLETE # success 

4984 else: 

4985 raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state)) 

4986 

4987 def GSS_Passive( 

4988 self, 

4989 Context: CONTEXT, 

4990 token=None, 

4991 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

4992 ): 

4993 if Context is None: 

4994 Context = self.CONTEXT(True) 

4995 Context.passive = True 

4996 

4997 if Context.state == self.STATE.INIT or ( 

4998 # In DCE/RPC, there's an extra AP-REP sent from the client. 

4999 Context.state == self.STATE.SRV_SENT_APREP 

5000 and req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5001 ): 

5002 Context, _, status = self.GSS_Accept_sec_context( 

5003 Context, token, req_flags=req_flags 

5004 ) 

5005 if status in [GSS_S_CONTINUE_NEEDED, GSS_S_COMPLETE]: 

5006 Context.state = self.STATE.CLI_SENT_APREQ 

5007 else: 

5008 Context.state = self.STATE.FAILED 

5009 return Context, status 

5010 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5011 Context, _, status = self.GSS_Init_sec_context( 

5012 Context, token, req_flags=req_flags 

5013 ) 

5014 if status == GSS_S_COMPLETE: 

5015 Context.state = self.STATE.SRV_SENT_APREP 

5016 else: 

5017 Context.state == self.STATE.FAILED 

5018 return Context, status 

5019 

5020 # Unknown state. Don't crash though. 

5021 return Context, GSS_S_FAILURE 

5022 

5023 def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False): 

5024 if Context.IsAcceptor is not IsAcceptor: 

5025 return 

5026 # Swap everything 

5027 Context.SendSealKeyUsage, Context.RecvSealKeyUsage = ( 

5028 Context.RecvSealKeyUsage, 

5029 Context.SendSealKeyUsage, 

5030 ) 

5031 Context.SendSignKeyUsage, Context.RecvSignKeyUsage = ( 

5032 Context.RecvSignKeyUsage, 

5033 Context.SendSignKeyUsage, 

5034 ) 

5035 Context.IsAcceptor = not Context.IsAcceptor 

5036 

5037 def LegsAmount(self, Context: CONTEXT): 

5038 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5039 return 4 

5040 else: 

5041 return 2 

5042 

5043 def MaximumSignatureLength(self, Context: CONTEXT): 

5044 if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG: 

5045 # TODO: support DES 

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

5047 return 76 

5048 elif Context.KrbSessionKey.etype in [23, 24]: # RC4_HMAC 

5049 return 45 

5050 else: 

5051 raise NotImplementedError 

5052 else: 

5053 return 28 

5054 

5055 def canMechListMIC(self, Context: CONTEXT): 

5056 return bool(Context.KrbSessionKey)