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

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

1905 statements  

1# SPDX-License-Identifier: GPL-2.0-only 

2# This file is part of Scapy 

3# See https://scapy.net/ for more information 

4# Copyright (C) Gabriel Potter 

5 

6r""" 

7Kerberos V5 

8 

9Implements parts of: 

10 

11- Kerberos Network Authentication Service (V5): RFC4120 

12- Kerberos Version 5 GSS-API: RFC1964, RFC4121 

13- Kerberos Pre-Authentication: RFC6113 (FAST) 

14- Kerberos Principal Name Canonicalization and Cross-Realm Referrals: RFC6806 

15- Microsoft Windows 2000 Kerberos Change Password and Set Password Protocols: RFC3244 

16- PKINIT and its extensions: RFC4556, RFC8070, RFC8636 and [MS-PKCA] 

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

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

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

20 draft-ietf-kitten-iakerb-03 

21- Kerberos Protocol Extensions: [MS-KILE] 

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

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

24 

25 

26.. note:: 

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

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

29 

30Example decryption:: 

31 

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

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

34 83c0a87a9cc0a87a11c209005854f6ab2392c25bd650182014b6e00000000001316a8201\ 

35 2d30820129a103020105a20302010aa3633061304ca103020102a24504433041a0030201\ 

36 12a23a043848484decb01c9b62a1cabfbc3f2d1ed85aa5e093ba8358a8cea34d4393af93\ 

37 bf211e274fa58e814878db9f0d7a28d94e7327660db4f3704b3011a10402020080a20904\ 

38 073005a0030101ffa481b73081b4a00703050040810010a1123010a003020101a1093007\ 

39 1b0577696e3124a20e1b0c444f4d41494e2e4c4f43414ca321301fa003020102a1183016\ 

40 1b066b72627467741b0c444f4d41494e2e4c4f43414ca511180f32303337303931333032\ 

41 343830355aa611180f32303337303931333032343830355aa7060204701cc5d1a8153013\ 

42 0201120201110201170201180202ff79020103a91d301b3019a003020114a11204105749\ 

43 4e31202020202020202020202020")) 

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

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

46 e87127a819d42e69b5e22de0ddc63da80096d")) 

47 >>> enc.decrypt(k) 

48""" 

49 

50from collections import namedtuple, deque 

51from datetime import datetime, timedelta, timezone 

52from enum import IntEnum 

53 

54import os 

55import re 

56import socket 

57import struct 

58import threading 

59 

60from scapy.error import warning 

61import scapy.asn1.mib # noqa: F401 

62from scapy.asn1.ber import BER_id_dec, BER_Decoding_Error 

63from scapy.asn1.asn1 import ( 

64 ASN1_BIT_STRING, 

65 ASN1_BOOLEAN, 

66 ASN1_Class, 

67 ASN1_Codecs, 

68 ASN1_GENERAL_STRING, 

69 ASN1_GENERALIZED_TIME, 

70 ASN1_INTEGER, 

71 ASN1_OID, 

72 ASN1_STRING, 

73 ASN1_UTF8_STRING, 

74) 

75from scapy.asn1fields import ( 

76 ASN1F_BIT_STRING_ENCAPS, 

77 ASN1F_BOOLEAN, 

78 ASN1F_CHOICE, 

79 ASN1F_enum_INTEGER, 

80 ASN1F_FLAGS, 

81 ASN1F_GENERAL_STRING, 

82 ASN1F_GENERALIZED_TIME, 

83 ASN1F_INTEGER, 

84 ASN1F_OID, 

85 ASN1F_optional, 

86 ASN1F_PACKET, 

87 ASN1F_SEQUENCE_OF, 

88 ASN1F_SEQUENCE, 

89 ASN1F_STRING_ENCAPS, 

90 ASN1F_STRING_PacketField, 

91 ASN1F_STRING, 

92 ASN1F_UTF8_STRING, 

93) 

94from scapy.asn1packet import ASN1_Packet 

95from scapy.automaton import Automaton, ATMT, ObjectPipe 

96from scapy.config import conf 

97from scapy.compat import bytes_encode 

98from scapy.error import log_runtime 

99from scapy.fields import ( 

100 ConditionalField, 

101 FieldLenField, 

102 FlagsField, 

103 IntEnumField, 

104 IntField, 

105 LEIntEnumField, 

106 LEShortEnumField, 

107 LEShortField, 

108 LenField, 

109 LongField, 

110 MayEnd, 

111 MultipleTypeField, 

112 PacketField, 

113 PacketLenField, 

114 PacketListField, 

115 PadField, 

116 ScalingField, 

117 ShortEnumField, 

118 ShortField, 

119 StrField, 

120 StrFieldUtf16, 

121 StrFixedLenEnumField, 

122 XByteField, 

123 XLEIntEnumField, 

124 XLEIntField, 

125 XLEShortField, 

126 XStrField, 

127 XStrFixedLenField, 

128 XStrLenField, 

129) 

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

131from scapy.supersocket import StreamSocket, SuperSocket 

132from scapy.utils import strrot, strxor 

133from scapy.volatile import GeneralizedTime, RandNum, RandBin 

134 

135from scapy.layers.gssapi import ( 

136 _GSSAPI_OIDS, 

137 _GSSAPI_SIGNATURE_OIDS, 

138 GSS_C_FLAGS, 

139 GSS_C_NO_CHANNEL_BINDINGS, 

140 GSS_QOP_REQ_FLAGS, 

141 GSS_S_BAD_BINDINGS, 

142 GSS_S_BAD_MECH, 

143 GSS_S_COMPLETE, 

144 GSS_S_CONTINUE_NEEDED, 

145 GSS_S_DEFECTIVE_CREDENTIAL, 

146 GSS_S_DEFECTIVE_TOKEN, 

147 GSS_S_FAILURE, 

148 GSS_S_FLAGS, 

149 GSSAPI_BLOB, 

150 GssChannelBindings, 

151 SSP, 

152) 

153from scapy.layers.inet import TCP, UDP 

154from scapy.layers.tls.cert import ( 

155 Cert, 

156 CertList, 

157 CertTree, 

158 CMS_Engine, 

159 PrivKey, 

160) 

161from scapy.layers.tls.crypto.hash import ( 

162 Hash_SHA, 

163 Hash_SHA256, 

164 Hash_SHA384, 

165 Hash_SHA512, 

166) 

167from scapy.layers.tls.crypto.groups import _ffdh_groups 

168from scapy.layers.windows.erref import STATUS_ERREF 

169from scapy.layers.x509 import ( 

170 _CMS_ENCAPSULATED, 

171 CMS_ContentInfo, 

172 CMS_IssuerAndSerialNumber, 

173 DHPublicKey, 

174 X509_AlgorithmIdentifier, 

175 X509_DirectoryName, 

176 X509_SubjectPublicKeyInfo, 

177 DomainParameters, 

178) 

179 

180# Redirect exports from RFC3961 

181try: 

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

183 from scapy.libs.rfc3961 import ( 

184 _rfc1964pad, 

185 ChecksumType, 

186 Cipher, 

187 decrepit_algorithms, 

188 EncryptionType, 

189 Hmac_MD5, 

190 Key, 

191 KRB_FX_CF2, 

192 octetstring2key, 

193 ) 

194except ImportError: 

195 pass 

196 

197 

198# Crypto imports 

199if conf.crypto_valid: 

200 from cryptography.hazmat.primitives.serialization import pkcs12 

201 from cryptography.hazmat.primitives.asymmetric import dh 

202 

203# Typing imports 

204from typing import ( 

205 List, 

206 Optional, 

207 Union, 

208) 

209 

210# kerberos APPLICATION 

211 

212 

213class ASN1_Class_KRB(ASN1_Class): 

214 name = "Kerberos" 

215 # APPLICATION + CONSTRUCTED = 0x40 | 0x20 

216 Token = 0x60 | 0 # GSSAPI 

217 Ticket = 0x60 | 1 

218 Authenticator = 0x60 | 2 

219 EncTicketPart = 0x60 | 3 

220 AS_REQ = 0x60 | 10 

221 AS_REP = 0x60 | 11 

222 TGS_REQ = 0x60 | 12 

223 TGS_REP = 0x60 | 13 

224 AP_REQ = 0x60 | 14 

225 AP_REP = 0x60 | 15 

226 PRIV = 0x60 | 21 

227 CRED = 0x60 | 22 

228 EncASRepPart = 0x60 | 25 

229 EncTGSRepPart = 0x60 | 26 

230 EncAPRepPart = 0x60 | 27 

231 EncKrbPrivPart = 0x60 | 28 

232 EncKrbCredPart = 0x60 | 29 

233 ERROR = 0x60 | 30 

234 

235 

236# RFC4120 sect 5.2 

237 

238 

239KerberosString = ASN1F_GENERAL_STRING 

240Realm = KerberosString 

241Int32 = ASN1F_INTEGER 

242UInt32 = ASN1F_INTEGER 

243 

244_PRINCIPAL_NAME_TYPES = { 

245 0: "NT-UNKNOWN", 

246 1: "NT-PRINCIPAL", 

247 2: "NT-SRV-INST", 

248 3: "NT-SRV-HST", 

249 4: "NT-SRV-XHST", 

250 5: "NT-UID", 

251 6: "NT-X500-PRINCIPAL", 

252 7: "NT-SMTP-NAME", 

253 10: "NT-ENTERPRISE", 

254} 

255 

256 

257class PrincipalName(ASN1_Packet): 

258 ASN1_codec = ASN1_Codecs.BER 

259 ASN1_root = ASN1F_SEQUENCE( 

260 ASN1F_enum_INTEGER( 

261 "nameType", 

262 0, 

263 _PRINCIPAL_NAME_TYPES, 

264 explicit_tag=0xA0, 

265 ), 

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

267 ) 

268 

269 def toString(self): 

270 """ 

271 Convert a PrincipalName back into its string representation. 

272 """ 

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

274 

275 @staticmethod 

276 def fromUPN(upn: str, canonicalize: bool = False): 

277 """ 

278 Create a PrincipalName from a UPN string. 

279 """ 

280 if canonicalize: 

281 return PrincipalName( 

282 nameString=[ASN1_GENERAL_STRING(upn)], 

283 nameType=ASN1_INTEGER(10), # NT-ENTERPRISE 

284 ) 

285 else: 

286 user, _ = _parse_upn(upn) 

287 return PrincipalName( 

288 nameString=[ASN1_GENERAL_STRING(user)], 

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

290 ) 

291 

292 @staticmethod 

293 def fromSPN(spn: str): 

294 """ 

295 Create a PrincipalName from a SPN string. 

296 """ 

297 spn, _ = _parse_spn(spn) 

298 if spn.startswith("krbtgt"): 

299 return PrincipalName( 

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

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

302 ) 

303 elif "/" in spn: 

304 return PrincipalName( 

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

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

307 ) 

308 else: 

309 # In case of U2U 

310 return PrincipalName( 

311 nameString=[ASN1_GENERAL_STRING(spn)], 

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

313 ) 

314 

315 

316KerberosTime = ASN1F_GENERALIZED_TIME 

317Microseconds = ASN1F_INTEGER 

318 

319 

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

321 

322_KRB_E_TYPES = { 

323 1: "DES-CBC-CRC", 

324 2: "DES-CBC-MD4", 

325 3: "DES-CBC-MD5", 

326 5: "DES3-CBC-MD5", 

327 7: "DES3-CBC-SHA1", 

328 9: "DSAWITHSHA1-CMSOID", 

329 10: "MD5WITHRSAENCRYPTION-CMSOID", 

330 11: "SHA1WITHRSAENCRYPTION-CMSOID", 

331 12: "RC2CBC-ENVOID", 

332 13: "RSAENCRYPTION-ENVOID", 

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

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

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

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

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

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

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

340 23: "RC4-HMAC", 

341 24: "RC4-HMAC-EXP", 

342 25: "CAMELLIA128-CTS-CMAC", 

343 26: "CAMELLIA256-CTS-CMAC", 

344} 

345 

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

347 

348_KRB_S_TYPES = { 

349 1: "CRC32", 

350 2: "RSA-MD4", 

351 3: "RSA-MD4-DES", 

352 4: "DES-MAC", 

353 5: "DES-MAC-K", 

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

355 7: "RSA-MD5", 

356 8: "RSA-MD5-DES", 

357 9: "RSA-MD5-DES3", 

358 10: "SHA1", 

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

360 13: "HMAC-SHA1-DES3", 

361 14: "SHA1", 

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

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

364 17: "CMAC-CAMELLIA128", 

365 18: "CMAC-CAMELLIA256", 

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

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

368 # RFC 4121 

369 0x8003: "KRB-AUTHENTICATOR", 

370 # [MS-KILE] 

371 0xFFFFFF76: "MD5", 

372 -138: "MD5", 

373} 

374 

375 

376class EncryptedData(ASN1_Packet): 

377 ASN1_codec = ASN1_Codecs.BER 

378 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

382 ) 

383 

384 def get_usage(self): 

385 """ 

386 Get current key usage number and encrypted class 

387 """ 

388 # RFC 4120 sect 7.5.1 

389 if self.underlayer: 

390 if isinstance(self.underlayer, PADATA): 

391 patype = self.underlayer.padataType 

392 if patype == 2: 

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

394 return 1, PA_ENC_TS_ENC 

395 elif patype == 138: 

396 # RFC6113 PA-ENC-TS-ENC 

397 return 54, PA_ENC_TS_ENC 

398 elif isinstance(self.underlayer, KRB_Ticket): 

399 # AS-REP Ticket and TGS-REP Ticket 

400 return 2, EncTicketPart 

401 elif isinstance(self.underlayer, KRB_AS_REP): 

402 # AS-REP encrypted part 

403 return 3, EncASRepPart 

404 elif isinstance(self.underlayer, KRB_KDC_REQ_BODY): 

405 # KDC-REQ enc-authorization-data 

406 return 4, AuthorizationData 

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

408 self.underlayer.underlayer, PADATA 

409 ): 

410 # TGS-REQ PA-TGS-REQ Authenticator 

411 return 7, KRB_Authenticator 

412 elif isinstance(self.underlayer, KRB_TGS_REP): 

413 # TGS-REP encrypted part 

414 return 8, EncTGSRepPart 

415 elif isinstance(self.underlayer, KRB_AP_REQ): 

416 # AP-REQ Authenticator 

417 return 11, KRB_Authenticator 

418 elif isinstance(self.underlayer, KRB_AP_REP): 

419 # AP-REP encrypted part 

420 return 12, EncAPRepPart 

421 elif isinstance(self.underlayer, KRB_PRIV): 

422 # KRB-PRIV encrypted part 

423 return 13, EncKrbPrivPart 

424 elif isinstance(self.underlayer, KRB_CRED): 

425 # KRB-CRED encrypted part 

426 return 14, EncKrbCredPart 

427 elif isinstance(self.underlayer, KrbFastArmoredReq): 

428 # KEY_USAGE_FAST_ENC 

429 return 51, KrbFastReq 

430 elif isinstance(self.underlayer, KrbFastArmoredRep): 

431 # KEY_USAGE_FAST_REP 

432 return 52, KrbFastResponse 

433 raise ValueError( 

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

435 ) 

436 

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

438 """ 

439 Decrypt and return the data contained in cipher. 

440 

441 :param key: the key to use for decryption 

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

443 Guessed otherwise 

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

445 Guessed otherwise (or bytes) 

446 """ 

447 if key_usage_number is None: 

448 key_usage_number, cls = self.get_usage() 

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

450 if cls: 

451 try: 

452 return cls(d) 

453 except BER_Decoding_Error: 

454 if cls == EncASRepPart: 

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

456 # "Compatibility note: Some implementations unconditionally send an 

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

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

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

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

461 try: 

462 res = EncTGSRepPart(d) 

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

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

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

466 log_runtime.warning( 

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

468 ) 

469 return res 

470 except BER_Decoding_Error: 

471 pass 

472 raise 

473 return d 

474 

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

476 """ 

477 Encrypt text and set it into cipher. 

478 

479 :param key: the key to use for encryption 

480 :param text: the bytes value to encode 

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

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

483 Guessed otherwise 

484 """ 

485 if key_usage_number is None: 

486 key_usage_number = self.get_usage()[0] 

487 self.etype = key.etype 

488 self.cipher = ASN1_STRING( 

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

490 ) 

491 

492 

493class EncryptionKey(ASN1_Packet): 

494 ASN1_codec = ASN1_Codecs.BER 

495 ASN1_root = ASN1F_SEQUENCE( 

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

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

498 ) 

499 

500 def toKey(self): 

501 return Key( 

502 etype=self.keytype.val, 

503 key=self.keyvalue.val, 

504 ) 

505 

506 @classmethod 

507 def fromKey(self, key): 

508 return EncryptionKey( 

509 keytype=key.etype, 

510 keyvalue=key.key, 

511 ) 

512 

513 

514class _Checksum_Field(ASN1F_STRING_PacketField): 

515 def m2i(self, pkt, s): 

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

517 if not val[0].val: 

518 return val 

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

520 # Special case per RFC 4121 

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

522 return val 

523 

524 

525class Checksum(ASN1_Packet): 

526 ASN1_codec = ASN1_Codecs.BER 

527 ASN1_root = ASN1F_SEQUENCE( 

528 ASN1F_enum_INTEGER( 

529 "cksumtype", 

530 0, 

531 _KRB_S_TYPES, 

532 explicit_tag=0xA0, 

533 ), 

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

535 ) 

536 

537 def get_usage(self): 

538 """ 

539 Get current key usage number 

540 """ 

541 # RFC 4120 sect 7.5.1 

542 if self.underlayer: 

543 if isinstance(self.underlayer, KRB_Authenticator): 

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

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

546 return 6 

547 elif isinstance(self.underlayer, PA_FOR_USER): 

548 # [MS-SFU] sect 2.2.1 

549 return 17 

550 elif isinstance(self.underlayer, PA_S4U_X509_USER): 

551 # [MS-SFU] sect 2.2.2 

552 return 26 

553 elif isinstance(self.underlayer, AD_KDCIssued): 

554 # AD-KDC-ISSUED checksum 

555 return 19 

556 elif isinstance(self.underlayer, KrbFastArmoredReq): 

557 # KEY_USAGE_FAST_REQ_CHKSUM 

558 return 50 

559 elif isinstance(self.underlayer, KrbFastFinished): 

560 # KEY_USAGE_FAST_FINISHED 

561 return 53 

562 raise ValueError( 

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

564 ) 

565 

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

567 """ 

568 Verify a signature of text using a key. 

569 

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

571 :param text: the bytes to verify 

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

573 Guessed otherwise 

574 """ 

575 if key_usage_number is None: 

576 key_usage_number = self.get_usage() 

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

578 

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

580 """ 

581 Make a signature. 

582 

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

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

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

586 Guessed otherwise 

587 """ 

588 if key_usage_number is None: 

589 key_usage_number = self.get_usage() 

590 self.cksumtype = cksumtype or key.cksumtype 

591 self.checksum = ASN1_STRING( 

592 key.make_checksum( 

593 keyusage=key_usage_number, 

594 text=text, 

595 cksumtype=self.cksumtype, 

596 ) 

597 ) 

598 

599 

600KerberosFlags = ASN1F_FLAGS 

601 

602_ADDR_TYPES = { 

603 # RFC4120 sect 7.5.3 

604 0x02: "IPv4", 

605 0x03: "Directional", 

606 0x05: "ChaosNet", 

607 0x06: "XNS", 

608 0x07: "ISO", 

609 0x0C: "DECNET Phase IV", 

610 0x10: "AppleTalk DDP", 

611 0x14: "NetBios", 

612 0x18: "IPv6", 

613} 

614 

615 

616class HostAddress(ASN1_Packet): 

617 ASN1_codec = ASN1_Codecs.BER 

618 ASN1_root = ASN1F_SEQUENCE( 

619 ASN1F_enum_INTEGER( 

620 "addrType", 

621 0, 

622 _ADDR_TYPES, 

623 explicit_tag=0xA0, 

624 ), 

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

626 ) 

627 

628 

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

630 name, [], HostAddress, **kwargs 

631) 

632 

633 

634_AUTHORIZATIONDATA_VALUES = { 

635 # Filled below 

636} 

637 

638 

639class _AuthorizationData_value_Field(ASN1F_STRING_PacketField): 

640 def m2i(self, pkt, s): 

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

642 if not val[0].val: 

643 return val 

644 if pkt.adType.val in _AUTHORIZATIONDATA_VALUES: 

645 return ( 

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

647 val[1], 

648 ) 

649 return val 

650 

651 

652_AD_TYPES = { 

653 # RFC4120 sect 7.5.4 

654 1: "AD-IF-RELEVANT", 

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

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

657 4: "AD-KDC-ISSUED", 

658 5: "AD-AND-OR", 

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

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

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

662 64: "OSF-DCE", 

663 65: "SESAME", 

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

665 128: "AD-WIN2K-PAC", 

666 129: "AD-ETYPE-NEGOTIATION", 

667 # [MS-KILE] additions 

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

669 142: "KERB-LOCAL", 

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

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

672} 

673 

674 

675class AuthorizationDataItem(ASN1_Packet): 

676 ASN1_codec = ASN1_Codecs.BER 

677 ASN1_root = ASN1F_SEQUENCE( 

678 ASN1F_enum_INTEGER( 

679 "adType", 

680 0, 

681 _AD_TYPES, 

682 explicit_tag=0xA0, 

683 ), 

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

685 ) 

686 

687 

688class AuthorizationData(ASN1_Packet): 

689 ASN1_codec = ASN1_Codecs.BER 

690 ASN1_root = ASN1F_SEQUENCE_OF( 

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

692 ) 

693 

694 def getAuthData(self, adType): 

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

696 

697 

698AD_IF_RELEVANT = AuthorizationData 

699_AUTHORIZATIONDATA_VALUES[1] = AD_IF_RELEVANT 

700 

701 

702class AD_KDCIssued(ASN1_Packet): 

703 ASN1_codec = ASN1_Codecs.BER 

704 ASN1_root = ASN1F_SEQUENCE( 

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

706 ASN1F_optional( 

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

708 ), 

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

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

711 ) 

712 

713 

714_AUTHORIZATIONDATA_VALUES[4] = AD_KDCIssued 

715 

716 

717class AD_AND_OR(ASN1_Packet): 

718 ASN1_codec = ASN1_Codecs.BER 

719 ASN1_root = ASN1F_SEQUENCE( 

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

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

722 ) 

723 

724 

725_AUTHORIZATIONDATA_VALUES[5] = AD_AND_OR 

726 

727ADMANDATORYFORKDC = AuthorizationData 

728_AUTHORIZATIONDATA_VALUES[8] = ADMANDATORYFORKDC 

729 

730 

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

732_PADATA_TYPES = { 

733 1: "PA-TGS-REQ", 

734 2: "PA-ENC-TIMESTAMP", 

735 3: "PA-PW-SALT", 

736 11: "PA-ETYPE-INFO", 

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

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

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

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

741 18: "PA-PK-OCSP-RESPONSE", 

742 19: "PA-ETYPE-INFO2", 

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

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

745 128: "PA-PAC-REQUEST", 

746 129: "PA-FOR-USER", 

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

748 131: "PA-FOR-CHECK_DUPS", 

749 132: "PA-AS-CHECKSUM", 

750 133: "PA-FX-COOKIE", 

751 134: "PA-AUTHENTICATION-SET", 

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

753 136: "PA-FX-FAST", 

754 137: "PA-FX-ERROR", 

755 138: "PA-ENCRYPTED-CHALLENGE", 

756 141: "PA-OTP-CHALLENGE", 

757 142: "PA-OTP-REQUEST", 

758 143: "PA-OTP-CONFIRM", 

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

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

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

762 147: "PA-PKINIT-KX", 

763 148: "PA-PKU2U-NAME", 

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

765 150: "PA-AS-FRESHNESS", 

766 151: "PA-SPAKE", 

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

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

769 165: "PA-SUPPORTED-ENCTYPES", 

770 166: "PA-EXTENDED-ERROR", 

771 167: "PA-PAC-OPTIONS", 

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

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

774} 

775 

776_PADATA_CLASSES = { 

777 # Filled elsewhere in this file 

778} 

779 

780 

781# RFC4120 

782 

783 

784class _PADATA_value_Field(ASN1F_STRING_PacketField): 

785 """ 

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

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

788 """ 

789 

790 def m2i(self, pkt, s): 

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

792 if pkt.padataType.val in _PADATA_CLASSES: 

793 cls = _PADATA_CLASSES[pkt.padataType.val] 

794 if isinstance(cls, tuple): 

795 parent = pkt.underlayer or pkt.parent 

796 is_reply = False 

797 if parent is not None: 

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

799 is_reply = True 

800 else: 

801 parent = parent.underlayer or parent.parent 

802 is_reply = isinstance(parent, KRB_ERROR) 

803 cls = cls[is_reply] 

804 if not val[0].val: 

805 return val 

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

807 return val 

808 

809 

810class PADATA(ASN1_Packet): 

811 ASN1_codec = ASN1_Codecs.BER 

812 ASN1_root = ASN1F_SEQUENCE( 

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

814 _PADATA_value_Field( 

815 "padataValue", 

816 "", 

817 explicit_tag=0xA2, 

818 ), 

819 ) 

820 

821 

822# RFC 4120 sect 5.2.7.2 

823 

824 

825class PA_ENC_TS_ENC(ASN1_Packet): 

826 ASN1_codec = ASN1_Codecs.BER 

827 ASN1_root = ASN1F_SEQUENCE( 

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

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

830 ) 

831 

832 

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

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

835 

836 

837# RFC 4120 sect 5.2.7.4 

838 

839 

840class ETYPE_INFO_ENTRY(ASN1_Packet): 

841 ASN1_codec = ASN1_Codecs.BER 

842 ASN1_root = ASN1F_SEQUENCE( 

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

844 ASN1F_optional( 

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

846 ), 

847 ) 

848 

849 

850class ETYPE_INFO(ASN1_Packet): 

851 ASN1_codec = ASN1_Codecs.BER 

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

853 

854 

855_PADATA_CLASSES[11] = ETYPE_INFO 

856 

857# RFC 4120 sect 5.2.7.5 

858 

859 

860class ETYPE_INFO_ENTRY2(ASN1_Packet): 

861 ASN1_codec = ASN1_Codecs.BER 

862 ASN1_root = ASN1F_SEQUENCE( 

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

864 ASN1F_optional( 

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

866 ), 

867 ASN1F_optional( 

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

869 ), 

870 ) 

871 

872 

873class ETYPE_INFO2(ASN1_Packet): 

874 ASN1_codec = ASN1_Codecs.BER 

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

876 

877 

878_PADATA_CLASSES[19] = ETYPE_INFO2 

879 

880 

881# RFC8636 - PKINIT Algorithm Agility 

882 

883 

884class TD_CMS_DIGEST_ALGORITHMS(ASN1_Packet): 

885 ASN1_codec = ASN1_Codecs.BER 

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

887 

888 

889_PADATA_CLASSES[111] = TD_CMS_DIGEST_ALGORITHMS 

890 

891 

892# PADATA Extended with RFC6113 

893 

894 

895class PA_AUTHENTICATION_SET_ELEM(ASN1_Packet): 

896 ASN1_codec = ASN1_Codecs.BER 

897 ASN1_root = ASN1F_SEQUENCE( 

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

899 ASN1F_optional( 

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

901 ), 

902 ASN1F_optional( 

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

904 ), 

905 ) 

906 

907 

908class PA_AUTHENTICATION_SET(ASN1_Packet): 

909 ASN1_codec = ASN1_Codecs.BER 

910 ASN1_root = ASN1F_SEQUENCE_OF( 

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

912 ) 

913 

914 

915_PADATA_CLASSES[134] = PA_AUTHENTICATION_SET 

916 

917 

918# [MS-KILE] sect 2.2.3 

919 

920 

921class PA_PAC_REQUEST(ASN1_Packet): 

922 ASN1_codec = ASN1_Codecs.BER 

923 ASN1_root = ASN1F_SEQUENCE( 

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

925 ) 

926 

927 

928_PADATA_CLASSES[128] = PA_PAC_REQUEST 

929 

930 

931# [MS-KILE] sect 2.2.5 

932 

933 

934class LSAP_TOKEN_INFO_INTEGRITY(Packet): 

935 fields_desc = [ 

936 FlagsField( 

937 "Flags", 

938 0, 

939 -32, 

940 { 

941 0x00000001: "UAC-Restricted", 

942 }, 

943 ), 

944 LEIntEnumField( 

945 "TokenIL", 

946 0x00002000, 

947 { 

948 0x00000000: "Untrusted", 

949 0x00001000: "Low", 

950 0x00002000: "Medium", 

951 0x00003000: "High", 

952 0x00004000: "System", 

953 0x00005000: "Protected process", 

954 }, 

955 ), 

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

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

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

959 ] 

960 

961 

962# [MS-KILE] sect 2.2.6 

963 

964 

965class _KerbAdRestrictionEntry_Field(ASN1F_STRING_PacketField): 

966 def m2i(self, pkt, s): 

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

968 if not val[0].val: 

969 return val 

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

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

972 return val 

973 

974 

975class KERB_AD_RESTRICTION_ENTRY(ASN1_Packet): 

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

977 ASN1_codec = ASN1_Codecs.BER 

978 ASN1_root = ASN1F_SEQUENCE( 

979 ASN1F_SEQUENCE( 

980 ASN1F_enum_INTEGER( 

981 "restrictionType", 

982 0, 

983 {0: "LSAP_TOKEN_INFO_INTEGRITY"}, 

984 explicit_tag=0xA0, 

985 ), 

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

987 ) 

988 ) 

989 

990 

991_AUTHORIZATIONDATA_VALUES[141] = KERB_AD_RESTRICTION_ENTRY 

992 

993 

994# [MS-KILE] sect 3.2.5.8 

995 

996 

997class KERB_AUTH_DATA_AP_OPTIONS(Packet): 

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

999 fields_desc = [ 

1000 FlagsField( 

1001 "apOptions", 

1002 0x4000, 

1003 -32, 

1004 { 

1005 0x4000: "KERB_AP_OPTIONS_CBT", 

1006 0x8000: "KERB_AP_OPTIONS_UNVERIFIED_TARGET_NAME", 

1007 }, 

1008 ), 

1009 ] 

1010 

1011 

1012_AUTHORIZATIONDATA_VALUES[143] = KERB_AUTH_DATA_AP_OPTIONS 

1013 

1014 

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

1016 

1017 

1018class KERB_AUTH_DATA_CLIENT_TARGET(Packet): 

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

1020 fields_desc = [ 

1021 StrFieldUtf16("spn", ""), 

1022 ] 

1023 

1024 

1025_AUTHORIZATIONDATA_VALUES[144] = KERB_AUTH_DATA_CLIENT_TARGET 

1026 

1027 

1028# RFC6806 sect 6 

1029 

1030 

1031class KERB_AD_LOGIN_ALIAS(ASN1_Packet): 

1032 ASN1_codec = ASN1_Codecs.BER 

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

1034 

1035 

1036_AUTHORIZATIONDATA_VALUES[80] = KERB_AD_LOGIN_ALIAS 

1037 

1038 

1039# [MS-KILE] sect 2.2.8 

1040 

1041 

1042class PA_SUPPORTED_ENCTYPES(Packet): 

1043 fields_desc = [ 

1044 FlagsField( 

1045 "flags", 

1046 0, 

1047 -32, 

1048 [ 

1049 "DES-CBC-CRC", 

1050 "DES-CBC-MD5", 

1051 "RC4-HMAC", 

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

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

1054 ] 

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

1056 + [ 

1057 "FAST-supported", 

1058 "Compount-identity-supported", 

1059 "Claims-supported", 

1060 "Resource-SID-compression-disabled", 

1061 ], 

1062 ) 

1063 ] 

1064 

1065 

1066_PADATA_CLASSES[165] = PA_SUPPORTED_ENCTYPES 

1067 

1068# [MS-KILE] sect 2.2.10 

1069 

1070 

1071class PA_PAC_OPTIONS(ASN1_Packet): 

1072 ASN1_codec = ASN1_Codecs.BER 

1073 ASN1_root = ASN1F_SEQUENCE( 

1074 KerberosFlags( 

1075 "options", 

1076 "", 

1077 [ 

1078 "Claims", 

1079 "Branch-Aware", 

1080 "Forward-to-Full-DC", 

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

1082 ], 

1083 explicit_tag=0xA0, 

1084 ) 

1085 ) 

1086 

1087 

1088_PADATA_CLASSES[167] = PA_PAC_OPTIONS 

1089 

1090# [MS-KILE] sect 2.2.11 

1091 

1092 

1093class KERB_KEY_LIST_REQ(ASN1_Packet): 

1094 ASN1_codec = ASN1_Codecs.BER 

1095 ASN1_root = ASN1F_SEQUENCE_OF( 

1096 "keytypes", 

1097 [], 

1098 ASN1F_enum_INTEGER("", 0, _KRB_E_TYPES), 

1099 ) 

1100 

1101 

1102_PADATA_CLASSES[161] = KERB_KEY_LIST_REQ 

1103 

1104# [MS-KILE] sect 2.2.12 

1105 

1106 

1107class KERB_KEY_LIST_REP(ASN1_Packet): 

1108 ASN1_codec = ASN1_Codecs.BER 

1109 ASN1_root = ASN1F_SEQUENCE_OF( 

1110 "keys", 

1111 [], 

1112 ASN1F_PACKET("", None, EncryptionKey), 

1113 ) 

1114 

1115 

1116_PADATA_CLASSES[162] = KERB_KEY_LIST_REP 

1117 

1118# [MS-KILE] sect 2.2.13 

1119 

1120 

1121class KERB_SUPERSEDED_BY_USER(ASN1_Packet): 

1122 ASN1_codec = ASN1_Codecs.BER 

1123 ASN1_root = ASN1F_SEQUENCE( 

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

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

1126 ) 

1127 

1128 

1129_PADATA_CLASSES[170] = KERB_SUPERSEDED_BY_USER 

1130 

1131 

1132# [MS-KILE] sect 2.2.14 

1133 

1134 

1135class KERB_DMSA_KEY_PACKAGE(ASN1_Packet): 

1136 ASN1_codec = ASN1_Codecs.BER 

1137 ASN1_root = ASN1F_SEQUENCE( 

1138 ASN1F_SEQUENCE_OF( 

1139 "currentKeys", 

1140 [], 

1141 ASN1F_PACKET("", None, EncryptionKey), 

1142 explicit_tag=0xA0, 

1143 ), 

1144 ASN1F_optional( 

1145 ASN1F_SEQUENCE_OF( 

1146 "previousKeys", 

1147 [], 

1148 ASN1F_PACKET("", None, EncryptionKey), 

1149 explicit_tag=0xA1, 

1150 ), 

1151 ), 

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

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

1154 ) 

1155 

1156 

1157_PADATA_CLASSES[171] = KERB_DMSA_KEY_PACKAGE 

1158 

1159 

1160# RFC6113 sect 5.4.1 

1161 

1162 

1163class _KrbFastArmor_value_Field(ASN1F_STRING_PacketField): 

1164 def m2i(self, pkt, s): 

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

1166 if not val[0].val: 

1167 return val 

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

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

1170 return val 

1171 

1172 

1173class KrbFastArmor(ASN1_Packet): 

1174 ASN1_codec = ASN1_Codecs.BER 

1175 ASN1_root = ASN1F_SEQUENCE( 

1176 ASN1F_enum_INTEGER( 

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

1178 ), 

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

1180 ) 

1181 

1182 

1183# RFC6113 sect 5.4.2 

1184 

1185 

1186class KrbFastArmoredReq(ASN1_Packet): 

1187 ASN1_codec = ASN1_Codecs.BER 

1188 ASN1_root = ASN1F_SEQUENCE( 

1189 ASN1F_SEQUENCE( 

1190 ASN1F_optional( 

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

1192 ), 

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

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

1195 ) 

1196 ) 

1197 

1198 

1199class PA_FX_FAST_REQUEST(ASN1_Packet): 

1200 ASN1_codec = ASN1_Codecs.BER 

1201 ASN1_root = ASN1F_CHOICE( 

1202 "armoredData", 

1203 ASN1_STRING(""), 

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

1205 ) 

1206 

1207 

1208# RFC6113 sect 5.4.3 

1209 

1210 

1211class KrbFastArmoredRep(ASN1_Packet): 

1212 ASN1_codec = ASN1_Codecs.BER 

1213 ASN1_root = ASN1F_SEQUENCE( 

1214 ASN1F_SEQUENCE( 

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

1216 ) 

1217 ) 

1218 

1219 

1220class PA_FX_FAST_REPLY(ASN1_Packet): 

1221 ASN1_codec = ASN1_Codecs.BER 

1222 ASN1_root = ASN1F_CHOICE( 

1223 "armoredData", 

1224 ASN1_STRING(""), 

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

1226 ) 

1227 

1228 

1229class KrbFastFinished(ASN1_Packet): 

1230 ASN1_codec = ASN1_Codecs.BER 

1231 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

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

1237 ) 

1238 

1239 

1240class KrbFastResponse(ASN1_Packet): 

1241 ASN1_codec = ASN1_Codecs.BER 

1242 ASN1_root = ASN1F_SEQUENCE( 

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

1244 ASN1F_optional( 

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

1246 ), 

1247 ASN1F_optional( 

1248 ASN1F_PACKET( 

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

1250 ) 

1251 ), 

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

1253 ) 

1254 

1255 

1256_PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY) 

1257 

1258 

1259# RFC 4556 - PKINIT 

1260 

1261 

1262# sect 3.2.1 

1263 

1264 

1265class ExternalPrincipalIdentifier(ASN1_Packet): 

1266 ASN1_codec = ASN1_Codecs.BER 

1267 ASN1_root = ASN1F_SEQUENCE( 

1268 ASN1F_optional( 

1269 ASN1F_STRING_ENCAPS( 

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

1271 ), 

1272 ), 

1273 ASN1F_optional( 

1274 ASN1F_STRING_ENCAPS( 

1275 "issuerAndSerialNumber", 

1276 None, 

1277 CMS_IssuerAndSerialNumber, 

1278 implicit_tag=0x81, 

1279 ), 

1280 ), 

1281 ASN1F_optional( 

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

1283 ), 

1284 ) 

1285 

1286 

1287class PA_PK_AS_REQ(ASN1_Packet): 

1288 ASN1_codec = ASN1_Codecs.BER 

1289 ASN1_root = ASN1F_SEQUENCE( 

1290 ASN1F_STRING_ENCAPS( 

1291 "signedAuthpack", 

1292 CMS_ContentInfo(), 

1293 CMS_ContentInfo, 

1294 implicit_tag=0x80, 

1295 ), 

1296 ASN1F_optional( 

1297 ASN1F_SEQUENCE_OF( 

1298 "trustedCertifiers", 

1299 None, 

1300 ExternalPrincipalIdentifier, 

1301 explicit_tag=0xA1, 

1302 ), 

1303 ), 

1304 ASN1F_optional( 

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

1306 ), 

1307 ) 

1308 

1309 

1310_PADATA_CLASSES[16] = PA_PK_AS_REQ 

1311 

1312 

1313# [MS-PKCA] sect 2.2.3 

1314 

1315 

1316class PAChecksum2(ASN1_Packet): 

1317 ASN1_codec = ASN1_Codecs.BER 

1318 ASN1_root = ASN1F_SEQUENCE( 

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

1320 ASN1F_PACKET( 

1321 "algorithmIdentifier", 

1322 X509_AlgorithmIdentifier(), 

1323 X509_AlgorithmIdentifier, 

1324 explicit_tag=0xA1, 

1325 ), 

1326 ) 

1327 

1328 def verify(self, text): 

1329 """ 

1330 Verify a checksum of text. 

1331 

1332 :param text: the bytes to verify 

1333 """ 

1334 # [MS-PKCA] 2.2.3 - PAChecksum2 

1335 

1336 # Only some OIDs are supported. Dumb but readable code. 

1337 oid = self.algorithmIdentifier.algorithm.val 

1338 if oid == "1.3.14.3.2.26": 

1339 hashcls = Hash_SHA 

1340 elif oid == "2.16.840.1.101.3.4.2.1": 

1341 hashcls = Hash_SHA256 

1342 elif oid == "2.16.840.1.101.3.4.2.2": 

1343 hashcls = Hash_SHA384 

1344 elif oid == "2.16.840.1.101.3.4.2.3": 

1345 hashcls = Hash_SHA512 

1346 else: 

1347 raise ValueError("Bad PAChecksum2 checksum !") 

1348 

1349 if hashcls().digest(text) != self.checksum.val: 

1350 raise ValueError("Bad PAChecksum2 checksum !") 

1351 

1352 def make(self, text, h="sha256"): 

1353 """ 

1354 Make a checksum. 

1355 

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

1357 """ 

1358 # Only some OIDs are supported. Dumb but readable code. 

1359 if h == "sha1": 

1360 hashcls = Hash_SHA 

1361 self.algorithmIdentifier.algorithm = ASN1_OID("1.3.14.3.2.26") 

1362 elif h == "sha256": 

1363 hashcls = Hash_SHA256 

1364 self.algorithmIdentifier.algorithm = ASN1_OID("2.16.840.1.101.3.4.2.1") 

1365 elif h == "sha384": 

1366 hashcls = Hash_SHA384 

1367 self.algorithmIdentifier.algorithm = ASN1_OID("2.16.840.1.101.3.4.2.2") 

1368 elif h == "sha512": 

1369 hashcls = Hash_SHA512 

1370 self.algorithmIdentifier.algorithm = ASN1_OID("2.16.840.1.101.3.4.2.3") 

1371 else: 

1372 raise ValueError("Bad PAChecksum2 checksum !") 

1373 

1374 self.checksum = ASN1_STRING(hashcls().digest(text)) 

1375 

1376 

1377# still RFC 4556 sect 3.2.1 

1378 

1379 

1380class KRB_PKAuthenticator(ASN1_Packet): 

1381 ASN1_codec = ASN1_Codecs.BER 

1382 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

1386 ASN1F_optional( 

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

1388 ), 

1389 # RFC8070 extension 

1390 ASN1F_optional( 

1391 ASN1F_STRING("freshnessToken", None, explicit_tag=0xA4), 

1392 ), 

1393 # [MS-PKCA] sect 2.2.3 

1394 ASN1F_optional( 

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

1396 ), 

1397 ) 

1398 

1399 def make_checksum(self, text, h: str = "sha256"): 

1400 """ 

1401 Populate paChecksum 

1402 """ 

1403 # paChecksum (always sha-1) 

1404 self.paChecksum = ASN1_STRING(Hash_SHA().digest(text)) 

1405 

1406 # paChecksum2 

1407 if h != "sha1": 

1408 self.paChecksum2 = PAChecksum2() 

1409 self.paChecksum2.make(text, h=h) 

1410 

1411 def verify_checksum(self, text): 

1412 """ 

1413 Verify paChecksum and paChecksum2 

1414 """ 

1415 if self.paChecksum.val != Hash_SHA().digest(text): 

1416 raise ValueError("Bad paChecksum checksum !") 

1417 

1418 if self.paChecksum2 is not None: 

1419 self.paChecksum2.verify(text) 

1420 

1421 

1422# RFC8636 sect 6 

1423 

1424 

1425class KDFAlgorithmId(ASN1_Packet): 

1426 ASN1_codec = ASN1_Codecs.BER 

1427 ASN1_root = ASN1F_SEQUENCE( 

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

1429 ) 

1430 

1431 

1432# still RFC 4556 sect 3.2.1 

1433 

1434 

1435class KRB_AuthPack(ASN1_Packet): 

1436 ASN1_codec = ASN1_Codecs.BER 

1437 ASN1_root = ASN1F_SEQUENCE( 

1438 ASN1F_PACKET( 

1439 "pkAuthenticator", 

1440 KRB_PKAuthenticator(), 

1441 KRB_PKAuthenticator, 

1442 explicit_tag=0xA0, 

1443 ), 

1444 ASN1F_optional( 

1445 ASN1F_PACKET( 

1446 "clientPublicValue", 

1447 X509_SubjectPublicKeyInfo(), 

1448 X509_SubjectPublicKeyInfo, 

1449 explicit_tag=0xA1, 

1450 ), 

1451 ), 

1452 ASN1F_optional( 

1453 ASN1F_SEQUENCE_OF( 

1454 "supportedCMSTypes", 

1455 None, 

1456 X509_AlgorithmIdentifier, 

1457 explicit_tag=0xA2, 

1458 ), 

1459 ), 

1460 ASN1F_optional( 

1461 ASN1F_STRING("clientDHNonce", None, explicit_tag=0xA3), 

1462 ), 

1463 # RFC8636 extension 

1464 ASN1F_optional( 

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

1466 ), 

1467 ) 

1468 

1469 

1470_CMS_ENCAPSULATED["1.3.6.1.5.2.3.1"] = KRB_AuthPack 

1471 

1472# sect 3.2.3 

1473 

1474 

1475class DHRepInfo(ASN1_Packet): 

1476 ASN1_codec = ASN1_Codecs.BER 

1477 ASN1_root = ASN1F_SEQUENCE( 

1478 ASN1F_STRING_ENCAPS( 

1479 "dhSignedData", 

1480 CMS_ContentInfo(), 

1481 CMS_ContentInfo, 

1482 implicit_tag=0x80, 

1483 ), 

1484 ASN1F_optional( 

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

1486 ), 

1487 # RFC8636 extension 

1488 ASN1F_optional( 

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

1490 ), 

1491 ) 

1492 

1493 

1494class EncKeyPack(ASN1_Packet): 

1495 ASN1_codec = ASN1_Codecs.BER 

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

1497 

1498 

1499class PA_PK_AS_REP(ASN1_Packet): 

1500 ASN1_codec = ASN1_Codecs.BER 

1501 ASN1_root = ASN1F_CHOICE( 

1502 "rep", 

1503 ASN1_STRING(""), 

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

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

1506 ) 

1507 

1508 

1509_PADATA_CLASSES[17] = PA_PK_AS_REP 

1510 

1511 

1512class KDCDHKeyInfo(ASN1_Packet): 

1513 ASN1_codec = ASN1_Codecs.BER 

1514 ASN1_root = ASN1F_SEQUENCE( 

1515 ASN1F_BIT_STRING_ENCAPS( 

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

1517 ), 

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

1519 ASN1F_optional( 

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

1521 ), 

1522 ) 

1523 

1524 

1525_CMS_ENCAPSULATED["1.3.6.1.5.2.3.2"] = KDCDHKeyInfo 

1526 

1527# [MS-SFU] 

1528 

1529 

1530# sect 2.2.1 

1531class PA_FOR_USER(ASN1_Packet): 

1532 ASN1_codec = ASN1_Codecs.BER 

1533 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

1538 ) 

1539 

1540 

1541_PADATA_CLASSES[129] = PA_FOR_USER 

1542 

1543 

1544# sect 2.2.2 

1545 

1546 

1547class S4UUserID(ASN1_Packet): 

1548 ASN1_codec = ASN1_Codecs.BER 

1549 ASN1_root = ASN1F_SEQUENCE( 

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

1551 ASN1F_optional( 

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

1553 ), 

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

1555 ASN1F_optional( 

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

1557 ), 

1558 ASN1F_optional( 

1559 ASN1F_FLAGS( 

1560 "options", 

1561 "", 

1562 [ 

1563 "reserved", 

1564 "KDC_CHECK_LOGON_HOUR_RESTRICTIONS", 

1565 "USE_REPLY_KEY_USAGE", 

1566 "NT_AUTH_POLICY_NOT_REQUIRED", 

1567 "UNCONDITIONAL_DELEGATION", 

1568 ], 

1569 explicit_tag=0xA4, 

1570 ) 

1571 ), 

1572 ) 

1573 

1574 

1575class PA_S4U_X509_USER(ASN1_Packet): 

1576 ASN1_codec = ASN1_Codecs.BER 

1577 ASN1_root = ASN1F_SEQUENCE( 

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

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

1580 ) 

1581 

1582 

1583_PADATA_CLASSES[130] = PA_S4U_X509_USER 

1584 

1585 

1586# Back to RFC4120 

1587 

1588# sect 5.10 

1589KRB_MSG_TYPES = { 

1590 1: "Ticket", 

1591 2: "Authenticator", 

1592 3: "EncTicketPart", 

1593 10: "AS-REQ", 

1594 11: "AS-REP", 

1595 12: "TGS-REQ", 

1596 13: "TGS-REP", 

1597 14: "AP-REQ", 

1598 15: "AP-REP", 

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

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

1601 20: "KRB-SAFE", 

1602 21: "KRB-PRIV", 

1603 22: "KRB-CRED", 

1604 25: "EncASRepPart", 

1605 26: "EncTGSRepPart", 

1606 27: "EncAPRepPart", 

1607 28: "EncKrbPrivPart", 

1608 29: "EnvKrbCredPart", 

1609 30: "KRB-ERROR", 

1610} 

1611 

1612# sect 5.3 

1613 

1614 

1615class KRB_Ticket(ASN1_Packet): 

1616 ASN1_codec = ASN1_Codecs.BER 

1617 ASN1_root = ASN1F_SEQUENCE( 

1618 ASN1F_SEQUENCE( 

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

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

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

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

1623 ), 

1624 implicit_tag=ASN1_Class_KRB.Ticket, 

1625 ) 

1626 

1627 def getSPN(self): 

1628 return "%s@%s" % ( 

1629 self.sname.toString(), 

1630 self.realm.val.decode(), 

1631 ) 

1632 

1633 

1634class TransitedEncoding(ASN1_Packet): 

1635 ASN1_codec = ASN1_Codecs.BER 

1636 ASN1_root = ASN1F_SEQUENCE( 

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

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

1639 ) 

1640 

1641 

1642_TICKET_FLAGS = [ 

1643 "reserved", 

1644 "forwardable", 

1645 "forwarded", 

1646 "proxiable", 

1647 "proxy", 

1648 "may-postdate", 

1649 "postdated", 

1650 "invalid", 

1651 "renewable", 

1652 "initial", 

1653 "pre-authent", 

1654 "hw-authent", 

1655 "transited-since-policy-checked", 

1656 "ok-as-delegate", 

1657 "unused", 

1658 "canonicalize", # RFC6806 

1659 "anonymous", # RFC6112 + RFC8129 

1660] 

1661 

1662 

1663class EncTicketPart(ASN1_Packet): 

1664 ASN1_codec = ASN1_Codecs.BER 

1665 ASN1_root = ASN1F_SEQUENCE( 

1666 ASN1F_SEQUENCE( 

1667 KerberosFlags( 

1668 "flags", 

1669 "", 

1670 _TICKET_FLAGS, 

1671 explicit_tag=0xA0, 

1672 ), 

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

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

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

1676 ASN1F_PACKET( 

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

1678 ), 

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

1680 ASN1F_optional( 

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

1682 ), 

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

1684 ASN1F_optional( 

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

1686 ), 

1687 ASN1F_optional( 

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

1689 ), 

1690 ASN1F_optional( 

1691 ASN1F_PACKET( 

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

1693 ), 

1694 ), 

1695 ), 

1696 implicit_tag=ASN1_Class_KRB.EncTicketPart, 

1697 ) 

1698 

1699 

1700# sect 5.4.1 

1701 

1702 

1703class KRB_KDC_REQ_BODY(ASN1_Packet): 

1704 ASN1_codec = ASN1_Codecs.BER 

1705 ASN1_root = ASN1F_SEQUENCE( 

1706 KerberosFlags( 

1707 "kdcOptions", 

1708 "", 

1709 [ 

1710 "reserved", 

1711 "forwardable", 

1712 "forwarded", 

1713 "proxiable", 

1714 "proxy", 

1715 "allow-postdate", 

1716 "postdated", 

1717 "unused7", 

1718 "renewable", 

1719 "unused9", 

1720 "unused10", 

1721 "opt-hardware-auth", 

1722 "unused12", 

1723 "unused13", 

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

1725 "canonicalize", # RFC6806 

1726 "request-anonymous", # RFC6112 + RFC8129 

1727 ] 

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

1729 + [ 

1730 "disable-transited-check", 

1731 "renewable-ok", 

1732 "enc-tkt-in-skey", 

1733 "unused29", 

1734 "renew", 

1735 "validate", 

1736 ], 

1737 explicit_tag=0xA0, 

1738 ), 

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

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

1741 ASN1F_optional( 

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

1743 ), 

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

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

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

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

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

1749 ASN1F_optional( 

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

1751 ), 

1752 ASN1F_optional( 

1753 ASN1F_PACKET( 

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

1755 ), 

1756 ), 

1757 ASN1F_optional( 

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

1759 ), 

1760 ) 

1761 

1762 

1763KRB_KDC_REQ = ASN1F_SEQUENCE( 

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

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

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

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

1768) 

1769 

1770 

1771class KrbFastReq(ASN1_Packet): 

1772 # RFC6113 sect 5.4.2 

1773 ASN1_codec = ASN1_Codecs.BER 

1774 ASN1_root = ASN1F_SEQUENCE( 

1775 KerberosFlags( 

1776 "fastOptions", 

1777 "", 

1778 [ 

1779 "RESERVED", 

1780 "hide-client-names", 

1781 ] 

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

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

1784 explicit_tag=0xA0, 

1785 ), 

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

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

1788 ) 

1789 

1790 

1791class KRB_AS_REQ(ASN1_Packet): 

1792 ASN1_codec = ASN1_Codecs.BER 

1793 ASN1_root = ASN1F_SEQUENCE( 

1794 KRB_KDC_REQ, 

1795 implicit_tag=ASN1_Class_KRB.AS_REQ, 

1796 ) 

1797 

1798 

1799class KRB_TGS_REQ(ASN1_Packet): 

1800 ASN1_codec = ASN1_Codecs.BER 

1801 ASN1_root = ASN1F_SEQUENCE( 

1802 KRB_KDC_REQ, 

1803 implicit_tag=ASN1_Class_KRB.TGS_REQ, 

1804 ) 

1805 msgType = ASN1_INTEGER(12) 

1806 

1807 

1808# sect 5.4.2 

1809 

1810KRB_KDC_REP = ASN1F_SEQUENCE( 

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

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

1813 ASN1F_optional( 

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

1815 ), 

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

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

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

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

1820) 

1821 

1822 

1823class KRB_AS_REP(ASN1_Packet): 

1824 ASN1_codec = ASN1_Codecs.BER 

1825 ASN1_root = ASN1F_SEQUENCE( 

1826 KRB_KDC_REP, 

1827 implicit_tag=ASN1_Class_KRB.AS_REP, 

1828 ) 

1829 

1830 def getUPN(self): 

1831 return "%s@%s" % ( 

1832 self.cname.toString(), 

1833 self.crealm.val.decode(), 

1834 ) 

1835 

1836 

1837class KRB_TGS_REP(ASN1_Packet): 

1838 ASN1_codec = ASN1_Codecs.BER 

1839 ASN1_root = ASN1F_SEQUENCE( 

1840 KRB_KDC_REP, 

1841 implicit_tag=ASN1_Class_KRB.TGS_REP, 

1842 ) 

1843 

1844 def getUPN(self): 

1845 return "%s@%s" % ( 

1846 self.cname.toString(), 

1847 self.crealm.val.decode(), 

1848 ) 

1849 

1850 

1851class LastReqItem(ASN1_Packet): 

1852 ASN1_codec = ASN1_Codecs.BER 

1853 ASN1_root = ASN1F_SEQUENCE( 

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

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

1856 ) 

1857 

1858 

1859EncKDCRepPart = ASN1F_SEQUENCE( 

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

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

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

1863 ASN1F_optional( 

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

1865 ), 

1866 KerberosFlags( 

1867 "flags", 

1868 "", 

1869 _TICKET_FLAGS, 

1870 explicit_tag=0xA4, 

1871 ), 

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

1873 ASN1F_optional( 

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

1875 ), 

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

1877 ASN1F_optional( 

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

1879 ), 

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

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

1882 ASN1F_optional( 

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

1884 ), 

1885 # RFC6806 sect 11 

1886 ASN1F_optional( 

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

1888 ), 

1889) 

1890 

1891 

1892class EncASRepPart(ASN1_Packet): 

1893 ASN1_codec = ASN1_Codecs.BER 

1894 ASN1_root = ASN1F_SEQUENCE( 

1895 EncKDCRepPart, 

1896 implicit_tag=ASN1_Class_KRB.EncASRepPart, 

1897 ) 

1898 

1899 

1900class EncTGSRepPart(ASN1_Packet): 

1901 ASN1_codec = ASN1_Codecs.BER 

1902 ASN1_root = ASN1F_SEQUENCE( 

1903 EncKDCRepPart, 

1904 implicit_tag=ASN1_Class_KRB.EncTGSRepPart, 

1905 ) 

1906 

1907 

1908# sect 5.5.1 

1909 

1910 

1911class KRB_AP_REQ(ASN1_Packet): 

1912 ASN1_codec = ASN1_Codecs.BER 

1913 ASN1_root = ASN1F_SEQUENCE( 

1914 ASN1F_SEQUENCE( 

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

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

1917 KerberosFlags( 

1918 "apOptions", 

1919 "", 

1920 [ 

1921 "reserved", 

1922 "use-session-key", 

1923 "mutual-required", 

1924 ], 

1925 explicit_tag=0xA2, 

1926 ), 

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

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

1929 ), 

1930 implicit_tag=ASN1_Class_KRB.AP_REQ, 

1931 ) 

1932 

1933 

1934_PADATA_CLASSES[1] = KRB_AP_REQ 

1935 

1936 

1937class KRB_Authenticator(ASN1_Packet): 

1938 ASN1_codec = ASN1_Codecs.BER 

1939 ASN1_root = ASN1F_SEQUENCE( 

1940 ASN1F_SEQUENCE( 

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

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

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

1944 ASN1F_optional( 

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

1946 ), 

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

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

1949 ASN1F_optional( 

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

1951 ), 

1952 ASN1F_optional( 

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

1954 ), 

1955 ASN1F_optional( 

1956 ASN1F_PACKET( 

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

1958 ), 

1959 ), 

1960 ), 

1961 implicit_tag=ASN1_Class_KRB.Authenticator, 

1962 ) 

1963 

1964 

1965# sect 5.5.2 

1966 

1967 

1968class KRB_AP_REP(ASN1_Packet): 

1969 ASN1_codec = ASN1_Codecs.BER 

1970 ASN1_root = ASN1F_SEQUENCE( 

1971 ASN1F_SEQUENCE( 

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

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

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

1975 ), 

1976 implicit_tag=ASN1_Class_KRB.AP_REP, 

1977 ) 

1978 

1979 

1980class EncAPRepPart(ASN1_Packet): 

1981 ASN1_codec = ASN1_Codecs.BER 

1982 ASN1_root = ASN1F_SEQUENCE( 

1983 ASN1F_SEQUENCE( 

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

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

1986 ASN1F_optional( 

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

1988 ), 

1989 ASN1F_optional( 

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

1991 ), 

1992 ), 

1993 implicit_tag=ASN1_Class_KRB.EncAPRepPart, 

1994 ) 

1995 

1996 

1997# sect 5.7 

1998 

1999 

2000class KRB_PRIV(ASN1_Packet): 

2001 ASN1_codec = ASN1_Codecs.BER 

2002 ASN1_root = ASN1F_SEQUENCE( 

2003 ASN1F_SEQUENCE( 

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

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

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

2007 ), 

2008 implicit_tag=ASN1_Class_KRB.PRIV, 

2009 ) 

2010 

2011 

2012class EncKrbPrivPart(ASN1_Packet): 

2013 ASN1_codec = ASN1_Codecs.BER 

2014 ASN1_root = ASN1F_SEQUENCE( 

2015 ASN1F_SEQUENCE( 

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

2017 ASN1F_optional( 

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

2019 ), 

2020 ASN1F_optional( 

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

2022 ), 

2023 ASN1F_optional( 

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

2025 ), 

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

2027 ASN1F_optional( 

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

2029 ), 

2030 ), 

2031 implicit_tag=ASN1_Class_KRB.EncKrbPrivPart, 

2032 ) 

2033 

2034 

2035# sect 5.8 

2036 

2037 

2038class KRB_CRED(ASN1_Packet): 

2039 ASN1_codec = ASN1_Codecs.BER 

2040 ASN1_root = ASN1F_SEQUENCE( 

2041 ASN1F_SEQUENCE( 

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

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

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

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

2046 ), 

2047 implicit_tag=ASN1_Class_KRB.CRED, 

2048 ) 

2049 

2050 

2051class KrbCredInfo(ASN1_Packet): 

2052 ASN1_codec = ASN1_Codecs.BER 

2053 ASN1_root = ASN1F_SEQUENCE( 

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

2055 ASN1F_optional( 

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

2057 ), 

2058 ASN1F_optional( 

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

2060 ), 

2061 ASN1F_optional( 

2062 KerberosFlags( 

2063 "flags", 

2064 None, 

2065 _TICKET_FLAGS, 

2066 explicit_tag=0xA3, 

2067 ), 

2068 ), 

2069 ASN1F_optional( 

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

2071 ), 

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

2073 ASN1F_optional( 

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

2075 ), 

2076 ASN1F_optional( 

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

2078 ), 

2079 ASN1F_optional( 

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

2081 ), 

2082 ASN1F_optional( 

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

2084 ), 

2085 ASN1F_optional( 

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

2087 ), 

2088 ) 

2089 

2090 

2091class EncKrbCredPart(ASN1_Packet): 

2092 ASN1_codec = ASN1_Codecs.BER 

2093 ASN1_root = ASN1F_SEQUENCE( 

2094 ASN1F_SEQUENCE( 

2095 ASN1F_SEQUENCE_OF( 

2096 "ticketInfo", 

2097 [KrbCredInfo()], 

2098 KrbCredInfo, 

2099 explicit_tag=0xA0, 

2100 ), 

2101 ASN1F_optional( 

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

2103 ), 

2104 ASN1F_optional( 

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

2106 ), 

2107 ASN1F_optional( 

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

2109 ), 

2110 ASN1F_optional( 

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

2112 ), 

2113 ASN1F_optional( 

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

2115 ), 

2116 ), 

2117 implicit_tag=ASN1_Class_KRB.EncKrbCredPart, 

2118 ) 

2119 

2120 

2121# sect 5.9.1 

2122 

2123 

2124class MethodData(ASN1_Packet): 

2125 ASN1_codec = ASN1_Codecs.BER 

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

2127 

2128 

2129class _KRBERROR_data_Field(ASN1F_STRING_PacketField): 

2130 def m2i(self, pkt, s): 

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

2132 if not val[0].val: 

2133 return val 

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

2135 # 14: KDC_ERR_ETYPE_NOSUPP 

2136 # 24: KDC_ERR_PREAUTH_FAILED 

2137 # 25: KDC_ERR_PREAUTH_REQUIRED 

2138 # 36: KRB_AP_ERR_BADMATCH 

2139 # 80: KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED 

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

2141 elif pkt.errorCode.val in [6, 7, 12, 13, 18, 23, 29, 32, 41, 60, 62]: 

2142 # 6: KDC_ERR_C_PRINCIPAL_UNKNOWN 

2143 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

2144 # 12: KDC_ERR_POLICY 

2145 # 13: KDC_ERR_BADOPTION 

2146 # 18: KDC_ERR_CLIENT_REVOKED 

2147 # 23: KDC_ERR_KEY_EXPIRED 

2148 # 29: KDC_ERR_SVC_UNAVAILABLE 

2149 # 32: KRB_AP_ERR_TKT_EXPIRED 

2150 # 41: KRB_AP_ERR_MODIFIED 

2151 # 60: KRB_ERR_GENERIC 

2152 # 62: KERB_ERR_TYPE_EXTENDED 

2153 try: 

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

2155 except BER_Decoding_Error: 

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

2157 # Some types can also happen in FAST sessions 

2158 # 18: KDC_ERR_CLIENT_REVOKED 

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

2160 elif pkt.errorCode.val == 7: 

2161 # This looks like an undocumented structure. 

2162 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

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

2164 raise 

2165 elif pkt.errorCode.val == 69: 

2166 # KRB_AP_ERR_USER_TO_USER_REQUIRED 

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

2168 return val 

2169 

2170 

2171class KRB_ERROR(ASN1_Packet): 

2172 ASN1_codec = ASN1_Codecs.BER 

2173 ASN1_root = ASN1F_SEQUENCE( 

2174 ASN1F_SEQUENCE( 

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

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

2177 ASN1F_optional( 

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

2179 ), 

2180 ASN1F_optional( 

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

2182 ), 

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

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

2185 ASN1F_enum_INTEGER( 

2186 "errorCode", 

2187 0, 

2188 { 

2189 # RFC4120 sect 7.5.9 

2190 0: "KDC_ERR_NONE", 

2191 1: "KDC_ERR_NAME_EXP", 

2192 2: "KDC_ERR_SERVICE_EXP", 

2193 3: "KDC_ERR_BAD_PVNO", 

2194 4: "KDC_ERR_C_OLD_MAST_KVNO", 

2195 5: "KDC_ERR_S_OLD_MAST_KVNO", 

2196 6: "KDC_ERR_C_PRINCIPAL_UNKNOWN", 

2197 7: "KDC_ERR_S_PRINCIPAL_UNKNOWN", 

2198 8: "KDC_ERR_PRINCIPAL_NOT_UNIQUE", 

2199 9: "KDC_ERR_NULL_KEY", 

2200 10: "KDC_ERR_CANNOT_POSTDATE", 

2201 11: "KDC_ERR_NEVER_VALID", 

2202 12: "KDC_ERR_POLICY", 

2203 13: "KDC_ERR_BADOPTION", 

2204 14: "KDC_ERR_ETYPE_NOSUPP", 

2205 15: "KDC_ERR_SUMTYPE_NOSUPP", 

2206 16: "KDC_ERR_PADATA_TYPE_NOSUPP", 

2207 17: "KDC_ERR_TRTYPE_NOSUPP", 

2208 18: "KDC_ERR_CLIENT_REVOKED", 

2209 19: "KDC_ERR_SERVICE_REVOKED", 

2210 20: "KDC_ERR_TGT_REVOKED", 

2211 21: "KDC_ERR_CLIENT_NOTYET", 

2212 22: "KDC_ERR_SERVICE_NOTYET", 

2213 23: "KDC_ERR_KEY_EXPIRED", 

2214 24: "KDC_ERR_PREAUTH_FAILED", 

2215 25: "KDC_ERR_PREAUTH_REQUIRED", 

2216 26: "KDC_ERR_SERVER_NOMATCH", 

2217 27: "KDC_ERR_MUST_USE_USER2USER", 

2218 28: "KDC_ERR_PATH_NOT_ACCEPTED", 

2219 29: "KDC_ERR_SVC_UNAVAILABLE", 

2220 31: "KRB_AP_ERR_BAD_INTEGRITY", 

2221 32: "KRB_AP_ERR_TKT_EXPIRED", 

2222 33: "KRB_AP_ERR_TKT_NYV", 

2223 34: "KRB_AP_ERR_REPEAT", 

2224 35: "KRB_AP_ERR_NOT_US", 

2225 36: "KRB_AP_ERR_BADMATCH", 

2226 37: "KRB_AP_ERR_SKEW", 

2227 38: "KRB_AP_ERR_BADADDR", 

2228 39: "KRB_AP_ERR_BADVERSION", 

2229 40: "KRB_AP_ERR_MSG_TYPE", 

2230 41: "KRB_AP_ERR_MODIFIED", 

2231 42: "KRB_AP_ERR_BADORDER", 

2232 44: "KRB_AP_ERR_BADKEYVER", 

2233 45: "KRB_AP_ERR_NOKEY", 

2234 46: "KRB_AP_ERR_MUT_FAIL", 

2235 47: "KRB_AP_ERR_BADDIRECTION", 

2236 48: "KRB_AP_ERR_METHOD", 

2237 49: "KRB_AP_ERR_BADSEQ", 

2238 50: "KRB_AP_ERR_INAPP_CKSUM", 

2239 51: "KRB_AP_PATH_NOT_ACCEPTED", 

2240 52: "KRB_ERR_RESPONSE_TOO_BIG", 

2241 60: "KRB_ERR_GENERIC", 

2242 61: "KRB_ERR_FIELD_TOOLONG", 

2243 # RFC4556 

2244 62: "KDC_ERR_CLIENT_NOT_TRUSTED", 

2245 63: "KDC_ERR_KDC_NOT_TRUSTED", 

2246 64: "KDC_ERR_INVALID_SIG", 

2247 65: "KDC_ERR_KEY_TOO_WEAK", 

2248 66: "KDC_ERR_CERTIFICATE_MISMATCH", 

2249 67: "KRB_AP_ERR_NO_TGT", 

2250 68: "KDC_ERR_WRONG_REALM", 

2251 69: "KRB_AP_ERR_USER_TO_USER_REQUIRED", 

2252 70: "KDC_ERR_CANT_VERIFY_CERTIFICATE", 

2253 71: "KDC_ERR_INVALID_CERTIFICATE", 

2254 72: "KDC_ERR_REVOKED_CERTIFICATE", 

2255 73: "KDC_ERR_REVOCATION_STATUS_UNKNOWN", 

2256 74: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE", 

2257 75: "KDC_ERR_CLIENT_NAME_MISMATCH", 

2258 76: "KDC_ERR_KDC_NAME_MISMATCH", 

2259 77: "KDC_ERR_INCONSISTENT_KEY_PURPOSE", 

2260 78: "KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED", 

2261 79: "KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED", 

2262 80: "KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED", 

2263 81: "KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED", 

2264 # draft-ietf-kitten-iakerb 

2265 85: "KRB_AP_ERR_IAKERB_KDC_NOT_FOUND", 

2266 86: "KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE", 

2267 # RFC6113 

2268 90: "KDC_ERR_PREAUTH_EXPIRED", 

2269 91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED", 

2270 92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET", 

2271 93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS", 

2272 # RFC8636 

2273 100: "KDC_ERR_NO_ACCEPTABLE_KDF", 

2274 }, 

2275 explicit_tag=0xA6, 

2276 ), 

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

2278 ASN1F_optional( 

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

2280 ), 

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

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

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

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

2285 ), 

2286 implicit_tag=ASN1_Class_KRB.ERROR, 

2287 ) 

2288 

2289 def getSPN(self): 

2290 return "%s@%s" % ( 

2291 self.sname.toString(), 

2292 self.realm.val.decode(), 

2293 ) 

2294 

2295 

2296# PA-FX-ERROR 

2297_PADATA_CLASSES[137] = KRB_ERROR 

2298 

2299 

2300# [MS-KILE] sect 2.2.1 

2301 

2302 

2303class KERB_EXT_ERROR(Packet): 

2304 fields_desc = [ 

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

2306 XLEIntField("reserved", 0), 

2307 XLEIntField("flags", 0x00000001), 

2308 ] 

2309 

2310 

2311class KERB_EXT_ERROR_NTSTATUS(Packet): 

2312 fields_desc = [ 

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

2314 ] 

2315 

2316 

2317# [MS-KILE] sect 2.2.2 

2318 

2319 

2320class _Error_Field(ASN1F_STRING_PacketField): 

2321 def m2i(self, pkt, s): 

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

2323 if not val[0].val: 

2324 return val 

2325 if pkt.dataType.val == 1: # KERB_AP_ERR_TYPE_NTSTATUS 

2326 return KERB_EXT_ERROR_NTSTATUS(val[0].val, _underlayer=pkt), val[1] 

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

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

2329 return val 

2330 

2331 

2332class KERB_ERROR_DATA(ASN1_Packet): 

2333 ASN1_codec = ASN1_Codecs.BER 

2334 ASN1_root = ASN1F_SEQUENCE( 

2335 ASN1F_enum_INTEGER( 

2336 "dataType", 

2337 2, 

2338 { 

2339 1: "KERB_AP_ERR_TYPE_NTSTATUS", # from the wdk 

2340 2: "KERB_AP_ERR_TYPE_SKEW_RECOVERY", 

2341 3: "KERB_ERR_TYPE_EXTENDED", 

2342 }, 

2343 explicit_tag=0xA1, 

2344 ), 

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

2346 ) 

2347 

2348 

2349# This looks like an undocumented structure. 

2350 

2351 

2352class KERB_ERROR_UNK(ASN1_Packet): 

2353 ASN1_codec = ASN1_Codecs.BER 

2354 ASN1_root = ASN1F_SEQUENCE( 

2355 ASN1F_SEQUENCE( 

2356 ASN1F_enum_INTEGER( 

2357 "dataType", 

2358 0, 

2359 { 

2360 -128: "KDC_ERR_MUST_USE_USER2USER", 

2361 }, 

2362 explicit_tag=0xA0, 

2363 ), 

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

2365 ) 

2366 ) 

2367 

2368 

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

2370 

2371 

2372class KRB_TGT_REQ(ASN1_Packet): 

2373 ASN1_codec = ASN1_Codecs.BER 

2374 ASN1_root = ASN1F_SEQUENCE( 

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

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

2377 ASN1F_optional( 

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

2379 ), 

2380 ASN1F_optional( 

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

2382 ), 

2383 ) 

2384 

2385 

2386class KRB_TGT_REP(ASN1_Packet): 

2387 ASN1_codec = ASN1_Codecs.BER 

2388 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

2392 ) 

2393 

2394 

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

2396 

2397 

2398class KRB_FINISHED(ASN1_Packet): 

2399 ASN1_codec = ASN1_Codecs.BER 

2400 ASN1_root = ASN1F_SEQUENCE( 

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

2402 ) 

2403 

2404 

2405# RFC 6542 sect 3.1 

2406 

2407 

2408class KRB_GSS_EXT(Packet): 

2409 fields_desc = [ 

2410 IntEnumField( 

2411 "type", 

2412 0, 

2413 { 

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

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

2416 0x00000001: "GSS_EXTS_IAKERB_FINISHED", # not standard 

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

2418 }, 

2419 ), 

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

2421 MultipleTypeField( 

2422 [ 

2423 ( 

2424 PacketField("data", KRB_FINISHED(), KRB_FINISHED), 

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

2426 ), 

2427 ], 

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

2429 ), 

2430 ] 

2431 

2432 

2433# RFC 4121 sect 4.1.1 

2434 

2435 

2436class KRB_AuthenticatorChecksum(Packet): 

2437 fields_desc = [ 

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

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

2440 FlagsField( 

2441 "Flags", 

2442 0, 

2443 -32, 

2444 { 

2445 0x01: "GSS_C_DELEG_FLAG", 

2446 0x02: "GSS_C_MUTUAL_FLAG", 

2447 0x04: "GSS_C_REPLAY_FLAG", 

2448 0x08: "GSS_C_SEQUENCE_FLAG", 

2449 0x10: "GSS_C_CONF_FLAG", # confidentiality 

2450 0x20: "GSS_C_INTEG_FLAG", # integrity 

2451 # RFC4757 

2452 0x1000: "GSS_C_DCE_STYLE", 

2453 0x2000: "GSS_C_IDENTIFY_FLAG", 

2454 0x4000: "GSS_C_EXTENDED_ERROR_FLAG", 

2455 }, 

2456 ), 

2457 ConditionalField( 

2458 LEShortField("DlgOpt", 1), 

2459 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2460 ), 

2461 ConditionalField( 

2462 FieldLenField("Dlgth", None, length_of="Deleg", fmt="<H"), 

2463 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2464 ), 

2465 ConditionalField( 

2466 PacketLenField( 

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

2468 ), 

2469 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2470 ), 

2471 # Extensions: RFC 6542 sect 3.1 

2472 PacketListField("Exts", KRB_GSS_EXT(), KRB_GSS_EXT), 

2473 ] 

2474 

2475 

2476# Kerberos V5 GSS-API - RFC1964 and RFC4121 

2477 

2478_TOK_IDS = { 

2479 # RFC 1964 

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

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

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

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

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

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

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

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

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

2489 # RFC 4121 

2490 b"\x04\x04": "GSS_GetMIC", 

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

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

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

2494} 

2495_SGN_ALGS = { 

2496 0x00: "DES MAC MD5", 

2497 0x01: "MD2.5", 

2498 0x02: "DES MAC", 

2499 # RFC 4757 

2500 0x11: "HMAC", 

2501} 

2502_SEAL_ALGS = { 

2503 0: "DES", 

2504 0xFFFF: "none", 

2505 # RFC 4757 

2506 0x10: "RC4", 

2507} 

2508 

2509 

2510# RFC 1964 - sect 1.1 

2511 

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

2513_InitialContextTokens = {} # filled below 

2514 

2515 

2516class KRB_InnerToken(Packet): 

2517 name = "Kerberos v5 InnerToken" 

2518 fields_desc = [ 

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

2520 PacketField( 

2521 "root", 

2522 KRB_AP_REQ(), 

2523 lambda x, _parent: _InitialContextTokens.get( 

2524 _parent.TOK_ID, conf.raw_layer 

2525 )(x), 

2526 ), 

2527 ] 

2528 

2529 def mysummary(self): 

2530 return self.sprintf( 

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

2532 ) 

2533 

2534 def guess_payload_class(self, payload): 

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

2536 return conf.padding_layer 

2537 return Kerberos 

2538 

2539 @classmethod 

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

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

2542 # Older RFC1964 variants of the token have KRB_GSSAPI_Token wrapper 

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

2544 return KRB_GSSAPI_Token 

2545 return cls 

2546 

2547 

2548# RFC 4121 - sect 4.1 

2549 

2550 

2551class KRB_GSSAPI_Token(GSSAPI_BLOB): 

2552 name = "Kerberos GSSAPI-Token" 

2553 ASN1_codec = ASN1_Codecs.BER 

2554 ASN1_root = ASN1F_SEQUENCE( 

2555 ASN1F_OID("MechType", "1.2.840.113554.1.2.2"), 

2556 ASN1F_PACKET( 

2557 "innerToken", 

2558 KRB_InnerToken(), 

2559 KRB_InnerToken, 

2560 implicit_tag=0x0, 

2561 ), 

2562 implicit_tag=ASN1_Class_KRB.Token, 

2563 ) 

2564 

2565 

2566# RFC 1964 - sect 1.2.1 

2567 

2568 

2569class KRB_GSS_MIC_RFC1964(Packet): 

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

2571 fields_desc = [ 

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

2573 XLEIntField("Filler", 0xFFFFFFFF), 

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

2575 PadField( # sect 1.2.2.3 

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

2577 align=8, 

2578 padwith=b"\x04", 

2579 ), 

2580 ] 

2581 

2582 def default_payload_class(self, payload): 

2583 return conf.padding_layer 

2584 

2585 

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

2587 

2588# RFC 1964 - sect 1.2.2 

2589 

2590 

2591class KRB_GSS_Wrap_RFC1964(Packet): 

2592 name = "Kerberos v5 GSS_Wrap (RFC1964)" 

2593 fields_desc = [ 

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

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

2596 XLEShortField("Filler", 0xFFFF), 

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

2598 PadField( # sect 1.2.2.3 

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

2600 align=8, 

2601 padwith=b"\x04", 

2602 ), 

2603 # sect 1.2.2.3 

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

2605 ] 

2606 

2607 def default_payload_class(self, payload): 

2608 return conf.padding_layer 

2609 

2610 

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

2612 

2613 

2614# RFC 1964 - sect 1.2.2 

2615 

2616 

2617class KRB_GSS_Delete_sec_context_RFC1964(Packet): 

2618 name = "Kerberos v5 GSS_Delete_sec_context (RFC1964)" 

2619 fields_desc = KRB_GSS_MIC_RFC1964.fields_desc 

2620 

2621 

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

2623 

2624 

2625# RFC 4121 - sect 4.2.2 

2626_KRB5_GSS_Flags = [ 

2627 "SentByAcceptor", 

2628 "Sealed", 

2629 "AcceptorSubkey", 

2630] 

2631 

2632 

2633# RFC 4121 - sect 4.2.6.1 

2634 

2635 

2636class KRB_GSS_MIC(Packet): 

2637 name = "Kerberos v5 MIC Token" 

2638 fields_desc = [ 

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

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

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

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

2643 ] 

2644 

2645 def default_payload_class(self, payload): 

2646 return conf.padding_layer 

2647 

2648 

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

2650 

2651 

2652# RFC 4121 - sect 4.2.6.2 

2653 

2654 

2655class KRB_GSS_Wrap(Packet): 

2656 name = "Kerberos v5 Wrap Token" 

2657 fields_desc = [ 

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

2659 XByteField("Filler", 0xFF), 

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

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

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

2663 MultipleTypeField( 

2664 [ 

2665 ( 

2666 XStrField("Data", b""), 

2667 lambda pkt: pkt.Flags.Sealed, 

2668 ) 

2669 ], 

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

2671 ), 

2672 ] 

2673 

2674 def default_payload_class(self, payload): 

2675 return conf.padding_layer 

2676 

2677 

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

2679 

2680 

2681# [MS-NRPC] 3.5.4.3.1 in theory, dsgetdc.h (WinSDK) for details 

2682 

2683_GetDcName_Flags = [ 

2684 "DS_RETURN_FLAT_NAME", # 0x80000000 

2685 "DS_RETURN_DNS_NAME", # 0x40000000 

2686 "reserved2", # 0x20000000 

2687 "reserved3", # 0x10000000 

2688 "reserved4", # 0x08000000 

2689 "reserved5", # 0x04000000 

2690 "DS_DIRECTORY_SERVICE_13_REQUIRED", # 0x02000000 - Windows Server 2025 or later 

2691 "DS_KEY_LIST_SUPPORT_REQUIRED", # 0x01000000 

2692 "DS_DIRECTORY_SERVICE_10_REQUIRED", # 0x00800000 - Windows Server 2016 or later 

2693 "DS_DIRECTORY_SERVICE_9_REQUIRED", # 0x00400000 - Windows Server 2012R2 or later 

2694 "DS_DIRECTORY_SERVICE_8_REQUIRED", # 0x00200000 - Windows Server 2012 or later 

2695 "DS_WEB_SERVICE_REQUIRED", # 0x00100000 

2696 "DS_DIRECTORY_SERVICE_6_REQUIRED", # 0x00080000 - Windows Server 2008 or later 

2697 "DS_TRY_NEXTCLOSEST_SITE", # 0x00040000 

2698 "DS_IS_DNS_NAME", # 0x00020000 

2699 "DS_IS_FLAT_NAME", # 0x00010000 

2700 "DS_ONLY_LDAP_NEEDED", # 0x00008000 

2701 "DS_AVOID_SELF", # 0x00004000 

2702 "DS_GOOD_TIMESERV_PREFERRED", # 0x00002000 

2703 "DS_WRITABLE_REQUIRED", # 0x00001000 

2704 "DS_TIMESERV_REQUIRED", # 0x00000800 

2705 "DS_KDC_REQUIRED", # 0x00000400 

2706 "DS_IP_REQUIRED", # 0x00000200 

2707 "DS_BACKGROUND_ONLY", # 0x00000100 

2708 "DS_PDC_REQUIRED", # 0x00000080 

2709 "DS_GC_SERVER_REQUIRED", # 0x00000040 

2710 "DS_DIRECTORY_SERVICE_PREFERRED", # 0x00000020 

2711 "DS_DIRECTORY_SERVICE_REQUIRED", # 0x00000010 

2712 "reserved-28", # 0x00000008 

2713 "reserved-29", # 0x00000004 

2714 "reserved-30", # 0x00000002 

2715 "DS_FORCE_REDISCOVERY", # 0x00000001 

2716] 

2717 

2718 

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

2720 

2721 

2722class IAKERB_HEADER(ASN1_Packet): 

2723 ASN1_codec = ASN1_Codecs.BER 

2724 ASN1_root = ASN1F_SEQUENCE( 

2725 ASN1F_UTF8_STRING("targetRealm", "", explicit_tag=0xA1), 

2726 ASN1F_optional( 

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

2728 ), 

2729 # [MS-SPNG] addition. This is mentioned on [kitten] IETF mailing list 

2730 # (and dochelp@ answered with details, should be updated soon) 

2731 ASN1F_optional( 

2732 ASN1F_FLAGS( 

2733 "headerFlags", 

2734 None, 

2735 _GetDcName_Flags, 

2736 explicit_tag=0xA3, 

2737 ) 

2738 ), 

2739 ) 

2740 

2741 def default_payload_class(self, payload): 

2742 return conf.padding_layer 

2743 

2744 

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

2746 

2747 

2748# Register for GSSAPI 

2749 

2750# Kerberos 5 

2751_GSSAPI_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2752_GSSAPI_SIGNATURE_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2753# Kerberos 5 - U2U 

2754_GSSAPI_OIDS["1.2.840.113554.1.2.2.3"] = KRB_InnerToken 

2755# Kerberos 5 - IAKERB 

2756_GSSAPI_OIDS["1.3.6.1.5.2.5"] = KRB_InnerToken 

2757 

2758 

2759# Entry class 

2760 

2761# RFC4120 sect 5.10 

2762 

2763 

2764class Kerberos(ASN1_Packet): 

2765 ASN1_codec = ASN1_Codecs.BER 

2766 ASN1_root = ASN1F_CHOICE( 

2767 "root", 

2768 None, 

2769 # RFC4120 

2770 KRB_GSSAPI_Token, # [APPLICATION 0] 

2771 KRB_Ticket, # [APPLICATION 1] 

2772 KRB_Authenticator, # [APPLICATION 2] 

2773 KRB_AS_REQ, # [APPLICATION 10] 

2774 KRB_AS_REP, # [APPLICATION 11] 

2775 KRB_TGS_REQ, # [APPLICATION 12] 

2776 KRB_TGS_REP, # [APPLICATION 13] 

2777 KRB_AP_REQ, # [APPLICATION 14] 

2778 KRB_AP_REP, # [APPLICATION 15] 

2779 # RFC4120 

2780 KRB_ERROR, # [APPLICATION 30] 

2781 ) 

2782 

2783 def mysummary(self): 

2784 return self.root.summary() 

2785 

2786 

2787bind_bottom_up(UDP, Kerberos, sport=88) 

2788bind_bottom_up(UDP, Kerberos, dport=88) 

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

2790 

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

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

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

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

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

2796 

2797 

2798# RFC4120 sect 7.2.2 

2799 

2800 

2801class KerberosTCPHeader(Packet): 

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

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

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

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

2806 

2807 @classmethod 

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

2809 if len(data) < 4: 

2810 return None 

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

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

2813 return cls(data) 

2814 if len(data) > length + 4: 

2815 return cls(data[:length + 4]) / conf.padding_layer(data[length + 4:]) 

2816 

2817 

2818bind_layers(KerberosTCPHeader, Kerberos) 

2819 

2820bind_bottom_up(TCP, KerberosTCPHeader, sport=88) 

2821bind_layers(TCP, KerberosTCPHeader, dport=88) 

2822 

2823 

2824# RFC3244 sect 2 

2825 

2826 

2827class KPASSWD_REQ(Packet): 

2828 fields_desc = [ 

2829 ShortField("len", None), 

2830 ShortField("pvno", 0xFF80), 

2831 ShortField("apreqlen", None), 

2832 PacketLenField( 

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

2834 ), 

2835 ConditionalField( 

2836 PacketLenField( 

2837 "krbpriv", 

2838 KRB_PRIV(), 

2839 KRB_PRIV, 

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

2841 ), 

2842 lambda pkt: pkt.apreqlen != 0, 

2843 ), 

2844 ConditionalField( 

2845 PacketLenField( 

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

2847 ), 

2848 lambda pkt: pkt.apreqlen == 0, 

2849 ), 

2850 ] 

2851 

2852 def post_build(self, p, pay): 

2853 if self.len is None: 

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

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

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

2857 return p + pay 

2858 

2859 

2860class ChangePasswdData(ASN1_Packet): 

2861 ASN1_codec = ASN1_Codecs.BER 

2862 ASN1_root = ASN1F_SEQUENCE( 

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

2864 ASN1F_optional( 

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

2866 ), 

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

2868 ) 

2869 

2870 

2871class KPASSWD_REP(Packet): 

2872 fields_desc = [ 

2873 ShortField("len", None), 

2874 ShortField("pvno", 0x0001), 

2875 ShortField("apreplen", None), 

2876 PacketLenField( 

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

2878 ), 

2879 ConditionalField( 

2880 PacketLenField( 

2881 "krbpriv", 

2882 KRB_PRIV(), 

2883 KRB_PRIV, 

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

2885 ), 

2886 lambda pkt: pkt.apreplen != 0, 

2887 ), 

2888 ConditionalField( 

2889 PacketLenField( 

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

2891 ), 

2892 lambda pkt: pkt.apreplen == 0, 

2893 ), 

2894 ] 

2895 

2896 def post_build(self, p, pay): 

2897 if self.len is None: 

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

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

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

2901 return p + pay 

2902 

2903 def answers(self, other): 

2904 return isinstance(other, KPASSWD_REQ) 

2905 

2906 

2907KPASSWD_RESULTS = { 

2908 0: "KRB5_KPASSWD_SUCCESS", 

2909 1: "KRB5_KPASSWD_MALFORMED", 

2910 2: "KRB5_KPASSWD_HARDERROR", 

2911 3: "KRB5_KPASSWD_AUTHERROR", 

2912 4: "KRB5_KPASSWD_SOFTERROR", 

2913 5: "KRB5_KPASSWD_ACCESSDENIED", 

2914 6: "KRB5_KPASSWD_BAD_VERSION", 

2915 7: "KRB5_KPASSWD_INITIAL_FLAG_NEEDED", 

2916} 

2917 

2918 

2919class DOMAIN_PASSWORD_INFORMATION(Packet): 

2920 # [MS-SAMR] sect 2.2.3.5 

2921 fields_desc = [ 

2922 IntField("MinPasswordLength", 0), 

2923 IntField("PasswordHistoryLength", 0), 

2924 FlagsField( 

2925 "PasswordProperties", 

2926 0, 

2927 32, 

2928 { 

2929 0x00000001: "DOMAIN_PASSWORD_COMPLEX", 

2930 0x00000002: "DOMAIN_PASSWORD_NO_ANON_CHANGE", 

2931 0x00000004: "DOMAIN_PASSWORD_NO_CLEAR_CHANGE", 

2932 0x00000008: "DOMAIN_LOCKOUT_ADMINS", 

2933 0x00000010: "DOMAIN_PASSWORD_STORE_CLEARTEXT", 

2934 0x00000020: "DOMAIN_REFUSE_PASSWORD_CHANGE", 

2935 0x00000040: "DOMAIN_NO_LM_OWF_CHANGE", 

2936 }, 

2937 ), 

2938 ScalingField("MaxPasswordAge", 30 * 24 * 3600, scaling=1 / 1e7, fmt="!Q"), 

2939 ScalingField("MinPasswordAge", 0, scaling=1 / 1e7, fmt="!Q"), 

2940 ] 

2941 

2942 

2943class KPasswdResult(Packet): 

2944 # This is guessed from looking at MIT's implementation + ntsecapi.h 

2945 fields_desc = [ 

2946 ShortField("PasswordInfoValid", 0), 

2947 PacketField( 

2948 "DomainPasswordInfo", 

2949 DOMAIN_PASSWORD_INFORMATION(), 

2950 DOMAIN_PASSWORD_INFORMATION, 

2951 ), 

2952 ] 

2953 

2954 

2955class _KPasswdRepDataResult_Field(StrField): 

2956 def m2i(self, pkt, s): 

2957 val = super(_KPasswdRepDataResult_Field, self).m2i(pkt, s) 

2958 if len(val or b"") == 30: 

2959 # A 30 octets blob is most likely the AD policy block 

2960 return KPasswdResult(val) 

2961 return val 

2962 

2963 

2964class KPasswdRepData(Packet): 

2965 fields_desc = [ 

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

2967 _KPasswdRepDataResult_Field("resultString", ""), 

2968 ] 

2969 

2970 

2971class Kpasswd(Packet): 

2972 @classmethod 

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

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

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

2976 return KPASSWD_REQ 

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

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

2979 if asn1_tag == 14: 

2980 return KPASSWD_REQ 

2981 elif asn1_tag == 15: 

2982 return KPASSWD_REP 

2983 return KPASSWD_REQ 

2984 

2985 

2986bind_bottom_up(UDP, Kpasswd, sport=464) 

2987bind_bottom_up(UDP, Kpasswd, dport=464) 

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

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

2990 

2991 

2992class KpasswdTCPHeader(Packet): 

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

2994 

2995 @classmethod 

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

2997 if len(data) < 4: 

2998 return None 

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

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

3001 return cls(data) 

3002 if len(data) > length + 4: 

3003 return cls(data[:length + 4]) / conf.padding_layer(data[length + 4:]) 

3004 

3005 

3006bind_layers(KpasswdTCPHeader, Kpasswd) 

3007 

3008bind_bottom_up(TCP, KpasswdTCPHeader, sport=464) 

3009bind_layers(TCP, KpasswdTCPHeader, dport=464) 

3010 

3011# [MS-KKDCP] 

3012 

3013 

3014class KDC_PROXY_MESSAGE(ASN1_Packet): 

3015 ASN1_codec = ASN1_Codecs.BER 

3016 ASN1_root = ASN1F_SEQUENCE( 

3017 ASN1F_STRING_ENCAPS( 

3018 "kerbMessage", 

3019 KerberosTCPHeader(), 

3020 KerberosTCPHeader, 

3021 explicit_tag=0xA0, 

3022 ), 

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

3024 ASN1F_optional( 

3025 ASN1F_FLAGS( 

3026 "dclocatorHint", 

3027 None, 

3028 _GetDcName_Flags, 

3029 explicit_tag=0xA2, 

3030 ) 

3031 ), 

3032 ) 

3033 

3034 

3035class KdcProxySocket(SuperSocket): 

3036 """ 

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

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

3039 """ 

3040 

3041 def __init__( 

3042 self, 

3043 url, 

3044 targetDomain, 

3045 dclocatorHint=None, 

3046 no_check_certificate=False, 

3047 **kwargs, 

3048 ): 

3049 self.url = url 

3050 self.targetDomain = targetDomain 

3051 self.dclocatorHint = dclocatorHint 

3052 self.no_check_certificate = no_check_certificate 

3053 self.queue = deque() 

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

3055 

3056 def recv(self, x=None): 

3057 return self.queue.popleft() 

3058 

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

3060 from scapy.layers.http import HTTP_Client 

3061 

3062 cli = HTTP_Client(no_check_certificate=self.no_check_certificate) 

3063 try: 

3064 # sr it via the web client 

3065 resp = cli.request( 

3066 self.url, 

3067 Method="POST", 

3068 data=bytes( 

3069 # Wrap request in KDC_PROXY_MESSAGE 

3070 KDC_PROXY_MESSAGE( 

3071 kerbMessage=bytes(x), 

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

3073 # dclocatorHint is optional 

3074 dclocatorHint=self.dclocatorHint, 

3075 ) 

3076 ), 

3077 http_headers={ 

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

3079 "Pragma": "no-cache", 

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

3081 }, 

3082 ) 

3083 if resp and conf.raw_layer in resp: 

3084 # Parse the payload 

3085 resp = KDC_PROXY_MESSAGE(resp.load).kerbMessage 

3086 # We have an answer, queue it. 

3087 self.queue.append(resp) 

3088 else: 

3089 raise EOFError 

3090 finally: 

3091 cli.close() 

3092 

3093 @staticmethod 

3094 def select(sockets, remain=None): 

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

3096 

3097 

3098class IAKerbSocket(SuperSocket): 

3099 """ 

3100 Wrapper to forward messages back to our SPNEGO caller. 

3101 """ 

3102 

3103 def __init__( 

3104 self, 

3105 Context, 

3106 realm: str, 

3107 **kwargs, 

3108 ): 

3109 self.Context = Context 

3110 self.realm = realm.upper() 

3111 self.incoming = ObjectPipe("iak_incoming") 

3112 self.results = ObjectPipe("iak_results") 

3113 self.t = None 

3114 super(IAKerbSocket, self).__init__(**kwargs) 

3115 

3116 def recv(self, n=0, options=socket.MsgFlag(0)): 

3117 """ 

3118 recv when acting as a socket 

3119 """ 

3120 return self.incoming.recv(n=n, options=options) 

3121 

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

3123 """ 

3124 send when acting as a socket 

3125 """ 

3126 x = x[KerberosTCPHeader].payload 

3127 

3128 # Wrap in the IAKERB header 

3129 pkt = KRB_GSSAPI_Token( 

3130 MechType="1.3.6.1.5.2.5", # Kerberos 5 - IAKERB 

3131 innerToken=KRB_InnerToken( 

3132 TOK_ID=b"\x05\x01", 

3133 root=IAKERB_HEADER( 

3134 targetRealm=ASN1_UTF8_STRING( 

3135 self.realm, 

3136 ), 

3137 headerFlags="DS_FORCE_REDISCOVERY", 

3138 ) 

3139 / x, 

3140 ), 

3141 ) 

3142 self.results.send( 

3143 ( 

3144 self.Context, 

3145 pkt, 

3146 GSS_S_CONTINUE_NEEDED, 

3147 ) 

3148 ) 

3149 

3150 def handler(self, func, **kwargs): 

3151 """ 

3152 Handler to catch exceptions as part of the IAKerb socket thread 

3153 """ 

3154 try: 

3155 # Call initial function 

3156 result = func(**kwargs) 

3157 

3158 # Send result 

3159 self.results.send(result) 

3160 

3161 # If this isn't a GSS_S_CONTINUE_NEEDED status, then 

3162 # the IAKERB part is done ! (failure or success) 

3163 _, _, status = result 

3164 if status != GSS_S_CONTINUE_NEEDED: 

3165 self.Context.IAKerbSocket = None 

3166 self.shutdown() 

3167 

3168 except Exception as ex: 

3169 self.results.send(ex) 

3170 

3171 def run(self, func, **kwargs): 

3172 """ 

3173 Run the sub-function asynchronously as part of this IAKerb socket 

3174 """ 

3175 self.t = threading.Thread(target=self.handler, args=(func,), kwargs=kwargs) 

3176 self.t.start() 

3177 

3178 def unpack(self, input_token): 

3179 """ 

3180 Extract Kerberos token from IAKERB if it is, or return None if it's not 

3181 an IAKERB token. 

3182 """ 

3183 try: 

3184 # GSSAPI wrapping 

3185 input_token = input_token.root 

3186 except AttributeError: 

3187 pass 

3188 

3189 if input_token.MechType.val == "1.3.6.1.5.2.5": 

3190 return input_token.innerToken.payload 

3191 

3192 return None 

3193 

3194 def next(self, input_token=None): 

3195 """ 

3196 Called by GSS_Init_sec_context when the input token is a IAKERB proxy. 

3197 """ 

3198 if input_token is not None: 

3199 # Make available in the incoming buffer of the socket 

3200 self.incoming.send(input_token) 

3201 

3202 # Now wait for a response that the client will generate 

3203 try: 

3204 res = self.results.recv() 

3205 except IndexError: 

3206 raise EOFError 

3207 if isinstance(res, Exception): 

3208 # We also get the exceptions back from the thread 

3209 raise res 

3210 return res 

3211 

3212 def close(self): 

3213 # We don't want this to be closed when used as a socket. 

3214 pass 

3215 

3216 def shutdown(self): 

3217 self.incoming.close() 

3218 self.results.close() 

3219 

3220 def __del__(self): 

3221 self.shutdown() 

3222 

3223 @staticmethod 

3224 def select(sockets, remain=None): 

3225 mapping = {x.incoming: x for x in sockets if isinstance(x, IAKerbSocket)} 

3226 return [mapping[x] for x in ObjectPipe.select(mapping.keys(), remain=remain)] 

3227 

3228 

3229# Util functions 

3230 

3231 

3232class PKINIT_KEX_METHOD(IntEnum): 

3233 DIFFIE_HELLMAN = 1 

3234 PUBLIC_KEY = 2 

3235 

3236 

3237class KerberosClient(Automaton): 

3238 """ 

3239 Implementation of a Kerberos client. 

3240 

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

3242 wrap this client. 

3243 

3244 Common parameters: 

3245 

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

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

3248 :param upn: the UPN of the client. 

3249 :param canonicalize: request the UPN to be canonicalized. 

3250 :param password: the password of the client. 

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

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

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

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

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

3256 

3257 Advanced common parameters: 

3258 

3259 :param kdc_proxy: specify a KDC proxy url 

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

3261 :param fast: use FAST armoring 

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

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

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

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

3266 :param dhashes: specify the list of supported digest algorithms for PKINIT 

3267 (defaults to ["sha1", "sha256", "sha384", "sha512"]) 

3268 

3269 AS-REQ only: 

3270 

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

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

3273 :param ca: the CA list that verifies the peer (KDC) certificate. Typically 

3274 only the ROOT CA is required. 

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

3276 'password' is the password of the p12. 

3277 :param pkinit_kex_method: (advanced) whether to use the DIFFIE-HELLMAN method or the 

3278 Certificate based one for PKINIT. 

3279 

3280 TGS-REQ only: 

3281 

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

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

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

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

3286 :param u2u: sets the U2U flag 

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

3288 :param s4u2proxy: sets the S4U2Proxy flag 

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

3290 """ 

3291 

3292 RES_AS_MODE = namedtuple( 

3293 "AS_Result", ["asrep", "sessionkey", "kdcrep", "upn", "pa_type"] 

3294 ) 

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

3296 

3297 class MODE(IntEnum): 

3298 AS_REQ = 0 

3299 TGS_REQ = 1 

3300 GET_SALT = 2 

3301 

3302 def __init__( 

3303 self, 

3304 mode=MODE.AS_REQ, 

3305 ip: Optional[str] = None, 

3306 upn: Optional[str] = None, 

3307 canonicalize: bool = False, 

3308 password: Optional[str] = None, 

3309 key: Optional["Key"] = None, 

3310 realm: Optional[str] = None, 

3311 x509: Optional[Union[Cert, str]] = None, 

3312 x509key: Optional[Union[PrivKey, str]] = None, 

3313 ca: Optional[Union[CertTree, str]] = None, 

3314 no_verify_cert: bool = False, 

3315 p12: Optional[str] = None, 

3316 spn: Optional[str] = None, 

3317 ticket: Optional[KRB_Ticket] = None, 

3318 host: Optional[str] = None, 

3319 renew: bool = False, 

3320 additional_tickets: List[KRB_Ticket] = [], 

3321 u2u: bool = False, 

3322 for_user: Optional[str] = None, 

3323 s4u2proxy: bool = False, 

3324 dmsa: bool = False, 

3325 kdc_proxy: Optional[str] = None, 

3326 kdc_proxy_no_check_certificate: bool = False, 

3327 iakerb: bool = False, 

3328 iakerb_socket: Optional[IAKerbSocket] = None, 

3329 fast: bool = False, 

3330 armor_ticket: KRB_Ticket = None, 

3331 armor_ticket_upn: Optional[str] = None, 

3332 armor_ticket_skey: Optional["Key"] = None, 

3333 key_list_req: List["EncryptionType"] = [], 

3334 etypes: Optional[List["EncryptionType"]] = None, 

3335 dhashes: Optional[List[str]] = None, 

3336 pkinit_kex_method: PKINIT_KEX_METHOD = PKINIT_KEX_METHOD.DIFFIE_HELLMAN, 

3337 port: int = 88, 

3338 timeout: int = 5, 

3339 verbose: bool = True, 

3340 **kwargs, 

3341 ): 

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

3343 from scapy.layers.ldap import dclocator 

3344 

3345 # PKINIT checks 

3346 if p12 is not None: 

3347 # password should be None or bytes 

3348 if isinstance(password, str): 

3349 password = password.encode() 

3350 

3351 # Read p12/pfx. If it fails and no password was provided, prompt and 

3352 # retry once. 

3353 while True: 

3354 try: 

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

3356 x509key, x509, _ = pkcs12.load_key_and_certificates( 

3357 fd.read(), 

3358 password=password, 

3359 ) 

3360 break 

3361 except ValueError as ex: 

3362 if password is None: 

3363 # We don't have a password. Prompt and retry. 

3364 try: 

3365 from prompt_toolkit import prompt 

3366 

3367 password = prompt( 

3368 "Enter PKCS12 password: ", is_password=True 

3369 ) 

3370 except ImportError: 

3371 password = input("Enter PKCS12 password: ") 

3372 password = password.encode() 

3373 else: 

3374 raise ex 

3375 

3376 x509 = Cert(cryptography_obj=x509) 

3377 x509key = PrivKey(cryptography_obj=x509key) 

3378 elif x509 and x509key: 

3379 if not isinstance(x509, Cert): 

3380 x509 = Cert(x509) 

3381 if not isinstance(x509key, PrivKey): 

3382 x509key = PrivKey(x509key) 

3383 if ca and not isinstance(ca, CertList): 

3384 ca = CertList(ca) 

3385 if upn is None and x509: 

3386 # For PKINIT, get the UPN from the SAN, if possible and present 

3387 if realm is None: 

3388 raise ValueError( 

3389 "When using PKINIT, you must at least specify the realm= !" 

3390 ) 

3391 for ext in x509.extensions: 

3392 if ext.extnID.val == "2.5.29.17": # subjectAltName 

3393 generalName = ext.extnValue.subjectAltName[0].generalName 

3394 upn = generalName.value.val.decode("utf-8") 

3395 break 

3396 if upn is None: 

3397 raise ValueError( 

3398 "Could not find subjectAltName in certificate !" 

3399 " Please provide a UPN." 

3400 ) 

3401 canonicalize = True 

3402 

3403 # UPN, SPN and realm calculation 

3404 if not upn: 

3405 raise ValueError("Invalid upn") 

3406 if realm is None: 

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

3408 _, realm = _parse_upn(upn) 

3409 elif mode == self.MODE.TGS_REQ: 

3410 _, realm = _parse_spn(spn) 

3411 if not realm and ticket: 

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

3413 # of the ticket. 

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

3415 else: 

3416 raise ValueError("Invalid realm") 

3417 if not spn and mode == self.MODE.AS_REQ and realm: 

3418 spn = "krbtgt/" + realm 

3419 elif not spn: 

3420 raise ValueError("Invalid spn") 

3421 

3422 # Extra checks for specific requests 

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

3424 if not host: 

3425 raise ValueError("Invalid host") 

3426 if x509 is not None: 

3427 if x509key and not ca: 

3428 if not no_verify_cert: 

3429 raise ValueError( 

3430 "Using PKINIT without specifying the remote CA is unsafe !" 

3431 " Set no_verify_cert=True to bypass this check." 

3432 ) 

3433 else: 

3434 ca = [] 

3435 elif not x509key or not ca: 

3436 raise ValueError("Must provide both 'x509', 'x509key' and 'ca' !") 

3437 elif mode == self.MODE.TGS_REQ: 

3438 if not ticket: 

3439 raise ValueError("Invalid ticket") 

3440 

3441 if not ip and not kdc_proxy and not iakerb: 

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

3443 ip = dclocator( 

3444 realm, 

3445 timeout=1, 

3446 # Use connect mode instead of ldap for compatibility 

3447 # with MIT kerberos servers 

3448 mode="connect", 

3449 port=port, 

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

3451 ).ip 

3452 

3453 # Armoring checks 

3454 if fast: 

3455 if mode == self.MODE.AS_REQ: 

3456 # Requires an external ticket 

3457 if not armor_ticket or not armor_ticket_upn or not armor_ticket_skey: 

3458 raise ValueError( 

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

3460 "please provide the 3 required armor arguments" 

3461 ) 

3462 elif mode == self.MODE.TGS_REQ: 

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

3464 raise ValueError( 

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

3466 ) 

3467 

3468 # Provide default supported encryption types. For SALT mode, we discard 

3469 # the encryption types that don't have a salt. 

3470 if mode == self.MODE.GET_SALT: 

3471 if etypes is not None: 

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

3473 

3474 etypes = [ 

3475 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3476 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3477 ] 

3478 elif etypes is None: 

3479 etypes = [ 

3480 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3481 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3482 EncryptionType.RC4_HMAC, 

3483 EncryptionType.DES_CBC_MD5, 

3484 ] 

3485 self.etypes = etypes 

3486 

3487 self.mode = mode 

3488 

3489 self.result = None # Result 

3490 

3491 self._timeout = timeout 

3492 self._verbose = verbose 

3493 self._ip = ip 

3494 self._port = port 

3495 self.kdc_proxy = kdc_proxy 

3496 self.kdc_proxy_no_check_certificate = kdc_proxy_no_check_certificate 

3497 self.iakerb = iakerb 

3498 self.iakerb_socket = iakerb_socket 

3499 

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

3501 self.host = host.upper() 

3502 self.password = password and bytes_encode(password) 

3503 self.spn = spn 

3504 self.upn = upn 

3505 self.canonicalize = canonicalize # Whether we request canonicalization 

3506 self.realm = realm.upper() 

3507 self.x509 = x509 

3508 self.x509key = x509key 

3509 self.pkinit_kex_method = pkinit_kex_method 

3510 self.ticket = ticket 

3511 self.fast = fast 

3512 self.armor_ticket = armor_ticket 

3513 self.armor_ticket_upn = armor_ticket_upn 

3514 self.armor_ticket_skey = armor_ticket_skey 

3515 self.key_list_req = key_list_req 

3516 self.renew = renew 

3517 self.additional_tickets = additional_tickets # U2U + S4U2Proxy 

3518 self.u2u = u2u # U2U 

3519 self.for_user = for_user # FOR-USER 

3520 self.s4u2proxy = s4u2proxy # S4U2Proxy 

3521 self.dmsa = dmsa # DMSA 

3522 self.key = key 

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

3524 self.replykey = None # Key used for reply 

3525 # See RFC4120 - sect 7.2.2 

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

3527 self.should_followup = False 

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

3529 self.fast_req_sent = False 

3530 # Session parameters 

3531 if self.x509: 

3532 # Windows only assumes it needs a pre-auth when PKINIT is used, 

3533 # otherwise it waits to have a PREAUTH_REQUIRED error first. 

3534 self.pre_auth = True 

3535 else: 

3536 self.pre_auth = False 

3537 self.pa_type = None # preauth-type that's used 

3538 self.fast_rep = None 

3539 self.fast_error = None 

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

3541 self.fast_armorkey = None # The armor key 

3542 self.fxcookie = None 

3543 self.pkinit_dh_key = None 

3544 self.no_verify_cert = no_verify_cert 

3545 if ca is not None: 

3546 self.pkinit_cms = CMS_Engine(ca) 

3547 else: 

3548 self.pkinit_cms = None 

3549 if dhashes is None: 

3550 self.dhashes = ["sha1", "sha256", "sha384", "sha512"] 

3551 else: 

3552 self.dhashes = dhashes 

3553 

3554 # Launch the client 

3555 sock = self._connect() 

3556 super(KerberosClient, self).__init__( 

3557 sock=sock, 

3558 **kwargs, 

3559 ) 

3560 

3561 def _connect(self): 

3562 """ 

3563 Internal function to bind a socket to the DC. 

3564 This also takes care of an eventual KDC proxy and IAKERB. 

3565 """ 

3566 if self.kdc_proxy: 

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

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

3569 sock = KdcProxySocket( 

3570 url=self.kdc_proxy, 

3571 targetDomain=self.realm, 

3572 no_check_certificate=self.kdc_proxy_no_check_certificate, 

3573 ) 

3574 elif self.iakerb: 

3575 # If we are using IAKERB, use the IAKerbSocket we were given that 

3576 # takes our messages and transport them over GSSAPI. 

3577 sock = self.iakerb_socket 

3578 else: 

3579 sock = socket.socket() 

3580 sock.settimeout(self._timeout) 

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

3582 sock = StreamSocket(sock, KerberosTCPHeader) 

3583 return sock 

3584 

3585 def send(self, pkt): 

3586 """ 

3587 Sends a wrapped Kerberos packet 

3588 """ 

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

3590 

3591 def _show_krb_error(self, error): 

3592 """ 

3593 Displays a Kerberos error 

3594 """ 

3595 if error.root.errorCode == 0x07: 

3596 # KDC_ERR_S_PRINCIPAL_UNKNOWN 

3597 if ( 

3598 isinstance(error.root.eData, KERB_ERROR_UNK) 

3599 and error.root.eData.dataType == -128 

3600 ): 

3601 log_runtime.error( 

3602 "KerberosSSP: KDC requires U2U for SPN '%s' !" % error.root.getSPN() 

3603 ) 

3604 else: 

3605 log_runtime.error( 

3606 "KerberosSSP: KDC_ERR_S_PRINCIPAL_UNKNOWN for SPN '%s'" 

3607 % error.root.getSPN() 

3608 ) 

3609 else: 

3610 log_runtime.error(error.root.sprintf("KerberosSSP: Received %errorCode% !")) 

3611 if self._verbose: 

3612 error.show() 

3613 

3614 def _base_kdc_req(self, now_time): 

3615 """ 

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

3617 """ 

3618 kdcreq = KRB_KDC_REQ_BODY( 

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

3620 additionalTickets=None, 

3621 # Windows default 

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

3623 cname=None, 

3624 realm=ASN1_GENERAL_STRING(self.realm), 

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

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

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

3628 ) 

3629 if self.renew: 

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

3631 self.request_nonce = kdcreq.nonce.val 

3632 return kdcreq 

3633 

3634 def calc_fast_armorkey(self): 

3635 """ 

3636 Calculate and return the FAST armorkey 

3637 """ 

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

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

3640 # AS-REQ mode 

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

3642 

3643 self.fast_armorkey = KRB_FX_CF2( 

3644 self.fast_skey, 

3645 self.armor_ticket_skey, 

3646 b"subkeyarmor", 

3647 b"ticketarmor", 

3648 ) 

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

3650 # TGS-REQ: 2 cases 

3651 

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

3653 

3654 if not self.armor_ticket: 

3655 # Case 1: Implicit armoring 

3656 self.fast_armorkey = KRB_FX_CF2( 

3657 self.subkey, 

3658 self.key, 

3659 b"subkeyarmor", 

3660 b"ticketarmor", 

3661 ) 

3662 else: 

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

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

3665 

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

3667 

3668 explicit_armor_key = KRB_FX_CF2( 

3669 self.fast_skey, 

3670 self.armor_ticket_skey, 

3671 b"subkeyarmor", 

3672 b"ticketarmor", 

3673 ) 

3674 

3675 self.fast_armorkey = KRB_FX_CF2( 

3676 explicit_armor_key, 

3677 self.subkey, 

3678 b"explicitarmor", 

3679 b"tgsarmor", 

3680 ) 

3681 

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

3683 """ 

3684 :param kdc_req: the KDC_REQ_BODY to wrap 

3685 :param padata: the list of PADATA to wrap 

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

3687 """ 

3688 

3689 # Create the PA Fast request wrapper 

3690 pafastreq = PA_FX_FAST_REQUEST( 

3691 armoredData=KrbFastArmoredReq( 

3692 reqChecksum=Checksum(), 

3693 encFastReq=EncryptedData(), 

3694 ) 

3695 ) 

3696 

3697 if self.armor_ticket is not None: 

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

3699 

3700 pafastreq.armoredData.armor = KrbFastArmor( 

3701 armorType=1, # FX_FAST_ARMOR_AP_REQUEST 

3702 armorValue=KRB_AP_REQ( 

3703 ticket=self.armor_ticket, 

3704 authenticator=EncryptedData(), 

3705 ), 

3706 ) 

3707 

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

3709 _, crealm = _parse_upn(self.armor_ticket_upn) 

3710 authenticator = KRB_Authenticator( 

3711 crealm=ASN1_GENERAL_STRING(crealm), 

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

3713 cksum=None, 

3714 ctime=ASN1_GENERALIZED_TIME(now_time), 

3715 cusec=ASN1_INTEGER(0), 

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

3717 seqNumber=ASN1_INTEGER(0), 

3718 encAuthorizationData=None, 

3719 ) 

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

3721 self.armor_ticket_skey, 

3722 authenticator, 

3723 ) 

3724 

3725 # Sign the fast request wrapper 

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

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

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

3729 pafastreq.armoredData.reqChecksum.make( 

3730 self.fast_armorkey, 

3731 bytes(pa_tgsreq_ap), 

3732 ) 

3733 else: 

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

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

3736 # containing message" 

3737 pafastreq.armoredData.reqChecksum.make( 

3738 self.fast_armorkey, 

3739 bytes(kdc_req), 

3740 ) 

3741 

3742 # Build and encrypt the Fast request 

3743 fastreq = KrbFastReq( 

3744 padata=padata, 

3745 reqBody=kdc_req, 

3746 ) 

3747 pafastreq.armoredData.encFastReq.encrypt( 

3748 self.fast_armorkey, 

3749 fastreq, 

3750 ) 

3751 

3752 # Return the PADATA 

3753 return PADATA( 

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

3755 padataValue=pafastreq, 

3756 ) 

3757 

3758 def as_req(self): 

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

3760 

3761 # 1. Build and populate KDC-REQ 

3762 kdc_req = self._base_kdc_req(now_time=now_time) 

3763 kdc_req.addresses = [ 

3764 HostAddress( 

3765 addrType=ASN1_INTEGER(20), # Netbios 

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

3767 ) 

3768 ] 

3769 kdc_req.addresses = None 

3770 kdc_req.cname = PrincipalName.fromUPN(self.upn, canonicalize=self.canonicalize) 

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

3772 

3773 # 2. Build the list of PADATA 

3774 padata = [ 

3775 PADATA( 

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

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

3778 ) 

3779 ] 

3780 

3781 # Cookie support 

3782 if self.fxcookie: 

3783 padata.insert( 

3784 0, 

3785 PADATA( 

3786 padataType=133, # PA-FX-COOKIE 

3787 padataValue=self.fxcookie, 

3788 ), 

3789 ) 

3790 

3791 # FAST 

3792 if self.fast: 

3793 # Calculate the armor key 

3794 self.calc_fast_armorkey() 

3795 

3796 # [MS-KILE] sect 3.2.5.5 

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

3798 padata.append( 

3799 PADATA( 

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

3801 padataValue=PA_PAC_OPTIONS( 

3802 options="Claims", 

3803 ), 

3804 ) 

3805 ) 

3806 

3807 # Pre-auth is requested 

3808 if self.pre_auth: 

3809 if self.x509: 

3810 # Special PKINIT (RFC4556) factor 

3811 

3812 # RFC4556 - 3.2.1. Generation of Client Request 

3813 

3814 # RFC4556 - 3.2.1 - (5) AuthPack 

3815 authpack = KRB_AuthPack( 

3816 pkAuthenticator=KRB_PKAuthenticator( 

3817 ctime=ASN1_GENERALIZED_TIME(now_time), 

3818 cusec=ASN1_INTEGER(0), 

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

3820 ), 

3821 clientPublicValue=None, # Used only in DH mode 

3822 supportedCMSTypes=[], 

3823 clientDHNonce=None, 

3824 supportedKDFs=None, 

3825 ) 

3826 

3827 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

3828 # RFC4556 - 3.2.3.1. Diffie-Hellman Key Exchange 

3829 

3830 # We (and Windows) use modp2048 

3831 dh_parameters = _ffdh_groups["modp2048"][0] 

3832 self.pkinit_dh_key = dh_parameters.generate_private_key() 

3833 numbers = dh_parameters.parameter_numbers() 

3834 

3835 # We can't use 'public_bytes' because it's the PKCS#3 format, 

3836 # and we want the DomainParameters format. 

3837 authpack.clientPublicValue = X509_SubjectPublicKeyInfo( 

3838 signatureAlgorithm=X509_AlgorithmIdentifier( 

3839 algorithm=ASN1_OID("dhpublicnumber"), 

3840 parameters=DomainParameters( 

3841 p=ASN1_INTEGER(numbers.p), 

3842 g=ASN1_INTEGER(numbers.g), 

3843 # q: see ERRATA 1 of RFC4556 

3844 q=ASN1_INTEGER(numbers.q or (numbers.p - 1) // 2), 

3845 j=None, 

3846 ), 

3847 ), 

3848 subjectPublicKey=DHPublicKey( 

3849 y=ASN1_INTEGER( 

3850 self.pkinit_dh_key.public_key().public_numbers().y 

3851 ), 

3852 ), 

3853 ) 

3854 elif self.pkinit_kex_method == PKINIT_KEX_METHOD.PUBLIC_KEY: 

3855 # RFC4556 - 3.2.3.2. - Public Key Encryption 

3856 

3857 # Set supportedCMSTypes, supportedKDFs 

3858 authpack.supportedCMSTypes = [ 

3859 X509_AlgorithmIdentifier(algorithm=ASN1_OID(x)) 

3860 for x in [ 

3861 "ecdsa-with-SHA512", 

3862 "ecdsa-with-SHA256", 

3863 "sha512WithRSAEncryption", 

3864 "sha256WithRSAEncryption", 

3865 ] 

3866 ] 

3867 authpack.supportedKDFs = [ 

3868 KDFAlgorithmId(kdfId=ASN1_OID(x)) 

3869 for x in [ 

3870 "id-pkinit-kdf-sha256", 

3871 "id-pkinit-kdf-sha1", 

3872 "id-pkinit-kdf-sha512", 

3873 ] 

3874 ] 

3875 

3876 # XXX UNFINISHED 

3877 raise NotImplementedError 

3878 else: 

3879 raise ValueError 

3880 

3881 # Find a supported digest hash. Windows 25H2 still defaults 

3882 # to SHA1 unless a client policy has been applied. 

3883 dhash = next(iter(self.dhashes)) 

3884 

3885 # Populate paChecksum 

3886 authpack.pkAuthenticator.make_checksum( 

3887 bytes(kdc_req), 

3888 h=dhash, 

3889 ) 

3890 

3891 # Sign the AuthPack 

3892 signedAuthpack = self.pkinit_cms.sign( 

3893 authpack, 

3894 ASN1_OID("id-pkinit-authData"), 

3895 self.x509, 

3896 self.x509key, 

3897 dhash=dhash, 

3898 ) 

3899 

3900 # Build PA-DATA 

3901 self.pa_type = 16 # PA-PK-AS-REQ 

3902 pafactor = PADATA( 

3903 padataType=self.pa_type, 

3904 padataValue=PA_PK_AS_REQ( 

3905 signedAuthpack=signedAuthpack, 

3906 trustedCertifiers=None, 

3907 kdcPkId=None, 

3908 ), 

3909 ) 

3910 

3911 # RFC 4557 extension - OCSP 

3912 padata.insert( 

3913 0, 

3914 PADATA( 

3915 padataType=18, # PA-PK-OCSP-RESPONSE 

3916 ), 

3917 ) 

3918 else: 

3919 # Key-based factor 

3920 

3921 if self.fast: 

3922 # Special FAST factor 

3923 # RFC6113 sect 5.4.6 

3924 

3925 # Calculate the 'challenge key' 

3926 ts_key = KRB_FX_CF2( 

3927 self.fast_armorkey, 

3928 self.key, 

3929 b"clientchallengearmor", 

3930 b"challengelongterm", 

3931 ) 

3932 self.pa_type = 138 # PA-ENCRYPTED-CHALLENGE 

3933 pafactor = PADATA( 

3934 padataType=self.pa_type, 

3935 padataValue=EncryptedData(), 

3936 ) 

3937 else: 

3938 # Usual 'timestamp' factor 

3939 ts_key = self.key 

3940 self.pa_type = 2 # PA-ENC-TIMESTAMP 

3941 pafactor = PADATA( 

3942 padataType=self.pa_type, 

3943 padataValue=EncryptedData(), 

3944 ) 

3945 pafactor.padataValue.encrypt( 

3946 ts_key, 

3947 PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), 

3948 ) 

3949 

3950 # Insert Pre-Authentication data 

3951 padata.insert( 

3952 0, 

3953 pafactor, 

3954 ) 

3955 

3956 # FAST support 

3957 if self.fast: 

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

3959 # hidden inside the encrypted section. 

3960 padata = [ 

3961 self._fast_wrap( 

3962 kdc_req=kdc_req, 

3963 padata=padata, 

3964 now_time=now_time, 

3965 ) 

3966 ] 

3967 

3968 # 3. Build the request 

3969 asreq = Kerberos( 

3970 root=KRB_AS_REQ( 

3971 padata=padata, 

3972 reqBody=kdc_req, 

3973 ) 

3974 ) 

3975 

3976 # Note the reply key 

3977 self.replykey = self.key 

3978 

3979 return asreq 

3980 

3981 def tgs_req(self): 

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

3983 

3984 # Compute armor key for FAST 

3985 if self.fast: 

3986 self.calc_fast_armorkey() 

3987 

3988 # 1. Build and populate KDC-REQ 

3989 kdc_req = self._base_kdc_req(now_time=now_time) 

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

3991 

3992 # Additional tickets 

3993 if self.additional_tickets: 

3994 kdc_req.additionalTickets = self.additional_tickets 

3995 

3996 # U2U 

3997 if self.u2u: 

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

3999 

4000 # 2. Build the list of PADATA 

4001 padata = [] 

4002 

4003 # [MS-SFU] FOR-USER extension 

4004 if self.for_user is not None: 

4005 # [MS-SFU] note 4: 

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

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

4008 # certificate is available. 

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

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

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

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

4013 

4014 # 1. Add PA_S4U_X509_USER 

4015 pasfux509 = PA_S4U_X509_USER( 

4016 userId=S4UUserID( 

4017 nonce=kdc_req.nonce, 

4018 # [MS-SFU] note 5: 

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

4020 options="USE_REPLY_KEY_USAGE", 

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

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

4023 subjectCertificate=None, # TODO 

4024 ), 

4025 checksum=Checksum(), 

4026 ) 

4027 

4028 if self.dmsa: 

4029 # DMSA = set UNCONDITIONAL_DELEGATION to 1 

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

4031 

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

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

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

4035 pasfux509.checksum.make( 

4036 self.subkey or self.key, 

4037 bytes(pasfux509.userId), 

4038 cksumtype=ChecksumType.RSA_MD4, 

4039 ) 

4040 else: 

4041 pasfux509.checksum.make( 

4042 self.subkey or self.key, 

4043 bytes(pasfux509.userId), 

4044 ) 

4045 padata.append( 

4046 PADATA( 

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

4048 padataValue=pasfux509, 

4049 ) 

4050 ) 

4051 

4052 # 2. Add PA_FOR_USER 

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

4054 paforuser = PA_FOR_USER( 

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

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

4057 cksum=Checksum(), 

4058 ) 

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

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

4061 ) + ( 

4062 ( 

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

4064 + paforuser.userRealm.val 

4065 + paforuser.authPackage.val 

4066 ).encode() 

4067 ) 

4068 paforuser.cksum.make( 

4069 self.subkey or self.key, 

4070 S4UByteArray, 

4071 cksumtype=ChecksumType.HMAC_MD5, 

4072 ) 

4073 padata.append( 

4074 PADATA( 

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

4076 padataValue=paforuser, 

4077 ) 

4078 ) 

4079 

4080 # [MS-SFU] S4U2proxy - sect 3.1.5.2.1 

4081 if self.s4u2proxy: 

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

4083 padata.append( 

4084 PADATA( 

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

4086 padataValue=PA_PAC_OPTIONS( 

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

4088 ), 

4089 ) 

4090 ) 

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

4092 kdc_req.kdcOptions.set(14, 1) 

4093 

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

4095 if self.key_list_req: 

4096 padata.append( 

4097 PADATA( 

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

4099 padataValue=KERB_KEY_LIST_REQ( 

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

4101 ), 

4102 ) 

4103 ) 

4104 

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

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

4107 pa_tgs_req = PADATA( 

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

4109 padataValue=apreq, 

4110 ) 

4111 

4112 # 4. Populate it's authenticator 

4113 _, crealm = _parse_upn(self.upn) 

4114 authenticator = KRB_Authenticator( 

4115 crealm=ASN1_GENERAL_STRING(crealm), 

4116 cname=PrincipalName.fromUPN(self.upn, canonicalize=self.canonicalize), 

4117 cksum=None, 

4118 ctime=ASN1_GENERALIZED_TIME(now_time), 

4119 cusec=ASN1_INTEGER(0), 

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

4121 seqNumber=None, 

4122 encAuthorizationData=None, 

4123 ) 

4124 

4125 # Compute checksum 

4126 if self.key.cksumtype: 

4127 authenticator.cksum = Checksum() 

4128 authenticator.cksum.make( 

4129 self.key, 

4130 bytes(kdc_req), 

4131 ) 

4132 

4133 # Encrypt authenticator 

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

4135 

4136 # 5. Process FAST if required 

4137 if self.fast: 

4138 padata = [ 

4139 self._fast_wrap( 

4140 kdc_req=kdc_req, 

4141 padata=padata, 

4142 now_time=now_time, 

4143 pa_tgsreq_ap=apreq, 

4144 ) 

4145 ] 

4146 

4147 # 6. Add the final PADATA 

4148 padata.append(pa_tgs_req) 

4149 

4150 # 7. Build the request 

4151 tgsreq = Kerberos( 

4152 root=KRB_TGS_REQ( 

4153 padata=padata, 

4154 reqBody=kdc_req, 

4155 ) 

4156 ) 

4157 

4158 # Note the reply key 

4159 if self.subkey: 

4160 self.replykey = self.subkey 

4161 else: 

4162 self.replykey = self.key 

4163 

4164 return tgsreq 

4165 

4166 @ATMT.state(initial=1) 

4167 def BEGIN(self): 

4168 pass 

4169 

4170 @ATMT.condition(BEGIN) 

4171 def should_send_as_req(self): 

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

4173 raise self.SENT_AS_REQ() 

4174 

4175 @ATMT.condition(BEGIN) 

4176 def should_send_tgs_req(self): 

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

4178 raise self.SENT_TGS_REQ() 

4179 

4180 @ATMT.action(should_send_as_req) 

4181 def send_as_req(self): 

4182 self.send(self.as_req()) 

4183 

4184 @ATMT.action(should_send_tgs_req) 

4185 def send_tgs_req(self): 

4186 self.send(self.tgs_req()) 

4187 

4188 @ATMT.state() 

4189 def SENT_AS_REQ(self): 

4190 pass 

4191 

4192 @ATMT.state() 

4193 def SENT_TGS_REQ(self): 

4194 pass 

4195 

4196 def _process_padatas_and_key(self, padatas, etype: "EncryptionType" = None): 

4197 """ 

4198 Process the PADATA, and generate missing keys if required. 

4199 

4200 :param etype: (optional) If provided, the EncryptionType to use. 

4201 """ 

4202 salt = b"" 

4203 

4204 if etype is not None and etype not in self.etypes: 

4205 raise ValueError("The answered 'etype' key isn't supported by us !") 

4206 

4207 # 1. Process pa-data 

4208 if padatas is not None: 

4209 for padata in padatas: 

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

4211 # We obtain the salt for hash types that need it 

4212 elt = padata.padataValue.seq[0] 

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

4214 etype = elt.etype.val 

4215 if etype != EncryptionType.RC4_HMAC: 

4216 salt = elt.salt.val 

4217 

4218 elif padata.padataType == 0x11: # PA-PK-AS-REP 

4219 # PKINIT handling 

4220 

4221 # The steps are as follows: 

4222 # 1. Verify and extract the CMS response. The expected type 

4223 # is different depending on the used method. 

4224 # 2. Compute the replykey 

4225 

4226 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

4227 # Unpack KDCDHKeyInfo 

4228 keyinfo = self.pkinit_cms.verify( 

4229 padata.padataValue.rep.dhSignedData, 

4230 eContentType=ASN1_OID("id-pkinit-DHKeyData"), 

4231 no_verify_cert=self.no_verify_cert, 

4232 ) 

4233 

4234 # If 'etype' is None, we're in an error. Since we verified 

4235 # the CMS successfully, end here. 

4236 if etype is None: 

4237 continue 

4238 

4239 # Extract crypto parameters 

4240 y = keyinfo.subjectPublicKey.y.val 

4241 

4242 # Import into cryptography 

4243 params = self.pkinit_dh_key.parameters().parameter_numbers() 

4244 pubkey = dh.DHPublicNumbers(y, params).public_key() 

4245 

4246 # Calculate DHSharedSecret 

4247 DHSharedSecret = self.pkinit_dh_key.exchange(pubkey) 

4248 

4249 # RFC4556 3.2.3.1 - AS reply key is derived as follows 

4250 self.replykey = octetstring2key( 

4251 etype, 

4252 DHSharedSecret, 

4253 ) 

4254 

4255 else: 

4256 raise ValueError 

4257 

4258 elif padata.padataType == 111: # TD-CMS-DIGEST-ALGORITHMS 

4259 self.dhashes = [x.algorithm.oidname for x in padata.padataValue.seq] 

4260 

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

4262 # Get cookie and store it 

4263 self.fxcookie = padata.padataValue 

4264 

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

4266 # FAST handling: get the actual inner message and decrypt it 

4267 if isinstance(padata.padataValue, PA_FX_FAST_REPLY): 

4268 self.fast_rep = ( 

4269 padata.padataValue.armoredData.encFastRep.decrypt( 

4270 self.fast_armorkey, 

4271 ) 

4272 ) 

4273 

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

4275 # Get error and store it 

4276 self.fast_error = padata.padataValue 

4277 

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

4279 # Verify S4U checksum 

4280 key_usage_number = None 

4281 pasfux509 = padata.padataValue 

4282 # [MS-SFU] sect 2.2.2 

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

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

4285 key_usage_number = 27 

4286 pasfux509.checksum.verify( 

4287 self.key, 

4288 bytes(pasfux509.userId), 

4289 key_usage_number=key_usage_number, 

4290 ) 

4291 

4292 # 2. Update the current keys if necessary 

4293 

4294 # Compute client key if not already provided 

4295 if self.key is None and etype is not None and self.x509 is None: 

4296 self.key = Key.string_to_key( 

4297 etype, 

4298 self.password, 

4299 salt, 

4300 ) 

4301 

4302 # Strengthen the reply key with the fast reply, if necessary 

4303 if self.fast_rep and self.fast_rep.strengthenKey: 

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

4305 self.replykey = KRB_FX_CF2( 

4306 self.fast_rep.strengthenKey.toKey(), 

4307 self.replykey, 

4308 b"strengthenkey", 

4309 b"replykey", 

4310 ) 

4311 

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

4313 def receive_salt_mode(self, pkt): 

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

4315 # exit. 

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

4317 if Kerberos not in pkt: 

4318 raise self.FINAL() 

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

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

4321 raise self.FINAL() 

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

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

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

4325 elt = padata.padataValue.seq[0] 

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

4327 self.result = elt.salt.val 

4328 raise self.FINAL() 

4329 else: 

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

4331 raise self.FINAL() 

4332 

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

4334 def receive_krb_error_as_req(self, pkt): 

4335 # We check for Kerberos errors. 

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

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

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

4339 # Process PAs if available 

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

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

4342 

4343 # Special case for FAST errors 

4344 if self.fast_rep: 

4345 # This is actually a fast response error ! 

4346 frep, self.fast_rep = self.fast_rep, None 

4347 # Re-process PAs 

4348 self._process_padatas_and_key(frep.padata) 

4349 # Extract real Kerberos error from FAST message 

4350 ferr = Kerberos(root=self.fast_error) 

4351 self.fast_error = None 

4352 # Recurse 

4353 self.receive_krb_error_as_req(ferr) 

4354 return 

4355 

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

4357 if not self.key: 

4358 log_runtime.error( 

4359 "Got 'KDC_ERR_PREAUTH_REQUIRED', " 

4360 "but no possible key could be computed." 

4361 ) 

4362 raise self.FINAL() 

4363 self.should_followup = True 

4364 self.pre_auth = True 

4365 raise self.BEGIN() 

4366 elif pkt.root.errorCode == 80: # KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED 

4367 self.should_followup = True 

4368 raise self.BEGIN() 

4369 else: 

4370 self._show_krb_error(pkt) 

4371 raise self.FINAL() 

4372 

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

4374 def receive_as_rep(self, pkt): 

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

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

4377 

4378 @ATMT.eof(SENT_AS_REQ) 

4379 def retry_after_eof_in_apreq(self): 

4380 if self.should_followup: 

4381 # Reconnect and Restart 

4382 self.should_followup = False 

4383 self.update_sock(self._connect()) 

4384 raise self.BEGIN() 

4385 else: 

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

4387 raise self.FINAL() 

4388 

4389 @ATMT.action(receive_as_rep) 

4390 def decrypt_as_rep(self, pkt): 

4391 # Process PADATAs. This is important for FAST and PKINIT 

4392 self._process_padatas_and_key( 

4393 pkt.root.padata, 

4394 etype=pkt.root.encPart.etype.val, 

4395 ) 

4396 

4397 if not self.pre_auth: 

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

4399 

4400 # Process FAST response 

4401 if self.fast_rep: 

4402 # Verify the ticket-checksum 

4403 self.fast_rep.finished.ticketChecksum.verify( 

4404 self.fast_armorkey, 

4405 bytes(pkt.root.ticket), 

4406 ) 

4407 # Process pa of FAST response 

4408 self._process_padatas_and_key( 

4409 self.fast_rep.padata, 

4410 etype=pkt.root.encPart.etype.val, 

4411 ) 

4412 self.fast_rep = None 

4413 elif self.fast: 

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

4415 

4416 # Check for PKINIT 

4417 if self.x509 and self.replykey is None: 

4418 raise ValueError("PKINIT was used but no valid PA-PK-AS-REP was found !") 

4419 

4420 # Decrypt AS-REP response 

4421 enc = pkt.root.encPart 

4422 res = enc.decrypt(self.replykey) 

4423 if res.nonce.val != self.request_nonce: 

4424 raise ValueError("KDC reply nonce does not match request") 

4425 self.result = self.RES_AS_MODE( 

4426 pkt.root, 

4427 res.key.toKey(), 

4428 res, 

4429 pkt.root.getUPN(), 

4430 self.pa_type, 

4431 ) 

4432 

4433 @ATMT.receive_condition(SENT_TGS_REQ) 

4434 def receive_krb_error_tgs_req(self, pkt): 

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

4436 # Process PAs if available 

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

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

4439 

4440 if self.fast_rep: 

4441 # This is actually a fast response error ! 

4442 frep, self.fast_rep = self.fast_rep, None 

4443 # Re-process PAs 

4444 self._process_padatas_and_key(frep.padata) 

4445 # Extract real Kerberos error from FAST message 

4446 ferr = Kerberos(root=self.fast_error) 

4447 self.fast_error = None 

4448 # Recurse 

4449 self.receive_krb_error_tgs_req(ferr) 

4450 return 

4451 

4452 self._show_krb_error(pkt) 

4453 raise self.FINAL() 

4454 

4455 @ATMT.receive_condition(SENT_TGS_REQ) 

4456 def receive_tgs_rep(self, pkt): 

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

4458 if ( 

4459 not self.renew 

4460 and not self.dmsa 

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

4462 ): 

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

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

4465 

4466 @ATMT.action(receive_tgs_rep) 

4467 def decrypt_tgs_rep(self, pkt): 

4468 self._process_padatas_and_key(pkt.root.padata) 

4469 

4470 # Process FAST response 

4471 if self.fast_rep: 

4472 # Verify the ticket-checksum 

4473 self.fast_rep.finished.ticketChecksum.verify( 

4474 self.fast_armorkey, 

4475 bytes(pkt.root.ticket), 

4476 ) 

4477 self.fast_rep = None 

4478 elif self.fast: 

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

4480 

4481 # Decrypt TGS-REP response 

4482 enc = pkt.root.encPart 

4483 if self.subkey: 

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

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

4486 # authenticator subkey is used." 

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

4488 else: 

4489 res = enc.decrypt(self.replykey) 

4490 

4491 if res.nonce.val != self.request_nonce: 

4492 raise ValueError("KDC reply nonce does not match request") 

4493 

4494 # Store result 

4495 self.result = self.RES_TGS_MODE( 

4496 pkt.root, 

4497 res.key.toKey(), 

4498 res, 

4499 self.upn, 

4500 ) 

4501 

4502 @ATMT.state(final=1) 

4503 def FINAL(self): 

4504 pass 

4505 

4506 

4507def _parse_upn(upn): 

4508 """ 

4509 Extract the username and realm from full UPN 

4510 """ 

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

4512 if not m: 

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

4514 if "/" in upn: 

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

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

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

4518 raise ValueError(err) 

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

4520 user = m.group(1) 

4521 domain = m.group(3) 

4522 else: 

4523 user = m.group(3) 

4524 domain = m.group(1) 

4525 return user, domain 

4526 

4527 

4528def _parse_spn(spn): 

4529 """ 

4530 Extract ServiceName and realm from full SPN 

4531 """ 

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

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

4534 if not m: 

4535 try: 

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

4537 return _parse_upn(spn) 

4538 except ValueError: 

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

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

4541 

4542 

4543def _spn_are_equal(spn1, spn2): 

4544 """ 

4545 Check that two SPNs are equal. 

4546 """ 

4547 spn1, _ = _parse_spn(spn1) 

4548 spn2, _ = _parse_spn(spn2) 

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

4550 

4551 

4552def krb_as_req( 

4553 upn: Optional[str] = None, 

4554 spn: Optional[str] = None, 

4555 ip: Optional[str] = None, 

4556 key: Optional["Key"] = None, 

4557 password: Optional[str] = None, 

4558 realm: Optional[str] = None, 

4559 host: str = "WIN10", 

4560 p12: Optional[str] = None, 

4561 x509: Optional[Union[str, Cert]] = None, 

4562 x509key: Optional[Union[str, PrivKey]] = None, 

4563 **kwargs, 

4564): 

4565 r""" 

4566 Kerberos AS-Req 

4567 

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

4569 or "user@DOMAIN" 

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

4571 Defaults to "krbtgt/<realm>" 

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

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

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

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

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

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

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

4579 'password' is the password of the p12. 

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

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

4582 

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

4584 

4585 Example:: 

4586 

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

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

4589 

4590 Equivalent:: 

4591 

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

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

4594 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

4596 

4597 Example using PKINIT with a p12 ("password" is the password of the p12):: 

4598 

4599 >>> krb_as_req(p12="./store.p12", realm="DOMAIN.LOCAL", password="password") 

4600 """ 

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

4602 if password is None: 

4603 try: 

4604 from prompt_toolkit import prompt 

4605 

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

4607 except ImportError: 

4608 password = input("Enter password: ") 

4609 cli = KerberosClient( 

4610 mode=KerberosClient.MODE.AS_REQ, 

4611 realm=realm, 

4612 ip=ip, 

4613 spn=spn, 

4614 host=host, 

4615 upn=upn, 

4616 password=password, 

4617 key=key, 

4618 p12=p12, 

4619 x509=x509, 

4620 x509key=x509key, 

4621 **kwargs, 

4622 ) 

4623 cli.run() 

4624 cli.stop() 

4625 return cli.result 

4626 

4627 

4628def krb_tgs_req( 

4629 upn, 

4630 spn, 

4631 sessionkey, 

4632 ticket, 

4633 ip=None, 

4634 renew=False, 

4635 realm=None, 

4636 additional_tickets=[], 

4637 u2u=False, 

4638 etypes=None, 

4639 for_user=None, 

4640 s4u2proxy=False, 

4641 **kwargs, 

4642): 

4643 r""" 

4644 Kerberos TGS-Req 

4645 

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

4647 or "user@DOMAIN" 

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

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

4650 :param ticket: the tgt ticket 

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

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

4653 :param renew: ask for renewal 

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

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

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

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

4658 :param etypes: array of EncryptionType values. 

4659 By default: AES128, AES256, RC4, DES_MD5 

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

4661 S4U2Self extension. 

4662 

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

4664 

4665 Example:: 

4666 

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

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

4669 

4670 Equivalent:: 

4671 

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

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

4674 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

4676 """ 

4677 cli = KerberosClient( 

4678 mode=KerberosClient.MODE.TGS_REQ, 

4679 realm=realm, 

4680 upn=upn, 

4681 ip=ip, 

4682 spn=spn, 

4683 key=sessionkey, 

4684 ticket=ticket, 

4685 renew=renew, 

4686 additional_tickets=additional_tickets, 

4687 u2u=u2u, 

4688 etypes=etypes, 

4689 for_user=for_user, 

4690 s4u2proxy=s4u2proxy, 

4691 **kwargs, 

4692 ) 

4693 cli.run() 

4694 cli.stop() 

4695 return cli.result 

4696 

4697 

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

4699 """ 

4700 Kerberos AS-Req then TGS-Req 

4701 """ 

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

4703 if not res: 

4704 return 

4705 

4706 return krb_tgs_req( 

4707 upn=res.upn, # UPN might get canonicalized 

4708 spn=spn, 

4709 sessionkey=res.sessionkey, 

4710 ticket=res.asrep.ticket, 

4711 ip=ip, 

4712 **kwargs, 

4713 ) 

4714 

4715 

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

4717 """ 

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

4719 """ 

4720 if realm is None: 

4721 _, realm = _parse_upn(upn) 

4722 cli = KerberosClient( 

4723 mode=KerberosClient.MODE.GET_SALT, 

4724 realm=realm, 

4725 ip=ip, 

4726 spn="krbtgt/" + realm, 

4727 upn=upn, 

4728 host=host, 

4729 **kwargs, 

4730 ) 

4731 cli.run() 

4732 cli.stop() 

4733 return cli.result 

4734 

4735 

4736def kpasswd( 

4737 upn, 

4738 targetupn=None, 

4739 ip=None, 

4740 password=None, 

4741 newpassword=None, 

4742 key=None, 

4743 ticket=None, 

4744 realm=None, 

4745 ssp=None, 

4746 setpassword=None, 

4747 timeout=3, 

4748 port=464, 

4749 debug=0, 

4750 **kwargs, 

4751): 

4752 """ 

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

4754 

4755 :param upn: the UPN to use for authentication 

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

4757 same as upn. 

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

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

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

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

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

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

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

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

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

4767 """ 

4768 from scapy.layers.ldap import dclocator 

4769 

4770 if not realm: 

4771 _, realm = _parse_upn(upn) 

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

4773 if ip is None: 

4774 ip = dclocator( 

4775 realm, 

4776 timeout=timeout, 

4777 # Use connect mode instead of ldap for compatibility 

4778 # with MIT kerberos servers 

4779 mode="connect", 

4780 port=port, 

4781 debug=debug, 

4782 ).ip 

4783 if ssp is None and ticket is not None: 

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

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

4786 if tktspn == "krbtgt": 

4787 log_runtime.info( 

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

4789 ) 

4790 setpassword = True 

4791 resp = krb_tgs_req( 

4792 upn=upn, 

4793 spn=spn, 

4794 ticket=ticket, 

4795 sessionkey=key, 

4796 ip=ip, 

4797 debug=debug, 

4798 ) 

4799 if resp is None: 

4800 return 

4801 ticket = resp.tgsrep.ticket 

4802 key = resp.sessionkey 

4803 if setpassword is None: 

4804 setpassword = bool(targetupn) 

4805 elif setpassword and targetupn is None: 

4806 targetupn = upn 

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

4808 # Get a ticket for kadmin/changepw 

4809 if ssp is None: 

4810 if ticket is None: 

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

4812 resp = krb_as_req( 

4813 upn=upn, 

4814 spn=spn, 

4815 key=key, 

4816 ip=ip, 

4817 password=password, 

4818 debug=debug, 

4819 ) 

4820 if resp is None: 

4821 return 

4822 ticket = resp.asrep.ticket 

4823 key = resp.sessionkey 

4824 ssp = KerberosSSP( 

4825 UPN=upn, 

4826 SPN=spn, 

4827 ST=ticket, 

4828 KEY=key, 

4829 DC_IP=ip, 

4830 debug=debug, 

4831 **kwargs, 

4832 ) 

4833 Context, tok, status = ssp.GSS_Init_sec_context( 

4834 None, 

4835 req_flags=0, # No GSS_C_MUTUAL_FLAG 

4836 ) 

4837 if status != GSS_S_CONTINUE_NEEDED: 

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

4839 if tok: 

4840 tok.show() 

4841 return 

4842 apreq = tok.innerToken.root 

4843 # Connect 

4844 sock = socket.socket() 

4845 sock.settimeout(timeout) 

4846 sock.connect((ip, port)) 

4847 sock = StreamSocket(sock, KpasswdTCPHeader) 

4848 # Do KPASSWD request 

4849 if newpassword is None: 

4850 try: 

4851 from prompt_toolkit import prompt 

4852 

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

4854 except ImportError: 

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

4856 krbpriv = KRB_PRIV(encPart=EncryptedData()) 

4857 krbpriv.encPart.encrypt( 

4858 Context.KrbSessionKey, 

4859 EncKrbPrivPart( 

4860 sAddress=HostAddress( 

4861 addrType=ASN1_INTEGER(2), # IPv4 

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

4863 ), 

4864 userData=ASN1_STRING( 

4865 bytes( 

4866 ChangePasswdData( 

4867 newpasswd=newpassword, 

4868 targname=PrincipalName.fromUPN(targetupn), 

4869 targrealm=realm, 

4870 ) 

4871 ) 

4872 if setpassword 

4873 else newpassword 

4874 ), 

4875 timestamp=None, 

4876 usec=None, 

4877 seqNumber=Context.SendSeqNum, 

4878 ), 

4879 ) 

4880 resp = sock.sr1( 

4881 KpasswdTCPHeader() 

4882 / KPASSWD_REQ( 

4883 pvno=0xFF80 if setpassword else 1, 

4884 apreq=apreq, 

4885 krbpriv=krbpriv, 

4886 ), 

4887 timeout=timeout, 

4888 verbose=0, 

4889 ) 

4890 # Verify KPASSWD response 

4891 if not resp: 

4892 raise TimeoutError("KPASSWD_REQ timed out !") 

4893 if KPASSWD_REP not in resp: 

4894 resp.show() 

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

4896 Context, tok, status = ssp.GSS_Init_sec_context( 

4897 Context, 

4898 input_token=resp.aprep, 

4899 ) 

4900 if status != GSS_S_COMPLETE: 

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

4902 if tok: 

4903 tok.show() 

4904 return 

4905 # Parse answer KRB_PRIV 

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

4907 userRep = KPasswdRepData(krbanswer.userData.val) 

4908 if userRep.resultCode != 0: 

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

4910 userRep.show() 

4911 return 

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

4913 

4914 

4915# SSP 

4916 

4917 

4918class KerberosSSP(SSP): 

4919 """ 

4920 The KerberosSSP 

4921 

4922 Client settings: 

4923 

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

4925 If not provided, will be retrieved 

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

4927 target_name provided in the GSS_Init_sec_context 

4928 :param UPN: The client UPN 

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

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

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

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

4933 OR the session key associated with the TGT 

4934 OR the kerberos key associated with the UPN 

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

4936 password of the UPN. 

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

4938 :param IAKERB: (optional) use IAKERB when requesting tickets. 

4939 

4940 Server settings: 

4941 

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

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

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

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

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

4947 this IP using using the KEY when using U2U. 

4948 """ 

4949 

4950 auth_type = 0x10 

4951 

4952 class STATE(SSP.STATE): 

4953 INIT = 1 

4954 CLI_SENT_TGTREQ = 2 

4955 CLI_SENT_APREQ = 3 

4956 CLI_RCVD_APREP = 4 

4957 SRV_SENT_APREP = 5 

4958 FAILED = -1 

4959 

4960 class CONTEXT(SSP.CONTEXT): 

4961 __slots__ = [ 

4962 "SessionKey", 

4963 "ServerHostname", 

4964 "U2U", 

4965 "IAKERB", 

4966 "KrbSessionKey", # raw Key object 

4967 "ST", # the service ticket 

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

4969 "SeqNum", # for AP 

4970 "SendSeqNum", # for MIC 

4971 "RecvSeqNum", # for MIC 

4972 "IsAcceptor", 

4973 "SendSealKeyUsage", 

4974 "SendSignKeyUsage", 

4975 "RecvSealKeyUsage", 

4976 "RecvSignKeyUsage", 

4977 # server-only 

4978 "UPN", 

4979 "PAC", 

4980 # IAKERB 

4981 "IAKerbSocket", 

4982 ] 

4983 

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

4985 self.state = KerberosSSP.STATE.INIT 

4986 self.SessionKey = None 

4987 self.ServerHostname = None 

4988 self.U2U = False 

4989 self.IAKERB = False 

4990 self.SendSeqNum = 0 

4991 self.RecvSeqNum = 0 

4992 self.KrbSessionKey = None 

4993 self.ST = None 

4994 self.STSessionKey = None 

4995 self.IsAcceptor = IsAcceptor 

4996 self.UPN = None 

4997 self.PAC = None 

4998 self.IAKerbSocket = None 

4999 # [RFC 4121] sect 2 

5000 if IsAcceptor: 

5001 self.SendSealKeyUsage = 22 

5002 self.SendSignKeyUsage = 23 

5003 self.RecvSealKeyUsage = 24 

5004 self.RecvSignKeyUsage = 25 

5005 else: 

5006 self.SendSealKeyUsage = 24 

5007 self.SendSignKeyUsage = 25 

5008 self.RecvSealKeyUsage = 22 

5009 self.RecvSignKeyUsage = 23 

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

5011 

5012 def clifailure(self): 

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

5014 

5015 def __repr__(self): 

5016 if self.U2U: 

5017 return "KerberosSSP-U2U" 

5018 elif self.IAKERB: 

5019 return "KerberosSSP-IAKERB" 

5020 else: 

5021 return "KerberosSSP" 

5022 

5023 def __init__( 

5024 self, 

5025 ST=None, 

5026 UPN=None, 

5027 PASSWORD=None, 

5028 U2U=False, 

5029 IAKERB=False, 

5030 KEY=None, 

5031 SPN=None, 

5032 TGT=None, 

5033 DC_IP=None, 

5034 SKEY_TYPE=None, 

5035 debug=0, 

5036 **kwargs, 

5037 ): 

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

5039 

5040 self.ST = ST 

5041 self.UPN = UPN 

5042 self.KEY = KEY 

5043 self.SPN = SPN 

5044 self.TGT = TGT 

5045 self.TGTSessionKey = None 

5046 self.PASSWORD = PASSWORD 

5047 self.U2U = U2U 

5048 self.IAKERB = IAKERB 

5049 self.DC_IP = DC_IP 

5050 self.debug = debug 

5051 if SKEY_TYPE is None: 

5052 SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96 

5053 self.SKEY_TYPE = SKEY_TYPE 

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

5055 

5056 def __repr__(self): 

5057 if self.IAKERB: 

5058 return "<%s-IAKERB>" % self.__class__.__name__ 

5059 elif self.U2U: 

5060 return "<%s-U2U>" % self.__class__.__name__ 

5061 else: 

5062 return "<%s>" % self.__class__.__name__ 

5063 

5064 def GSS_Inquire_names_for_mech(self): 

5065 if self.IAKERB: 

5066 return ["1.3.6.1.5.2.5"] # Kerberos 5 - IAKERB 

5067 elif self.U2U: 

5068 return ["1.2.840.113554.1.2.2.3"] # Kerberos 5 - User to User 

5069 else: 

5070 return [ 

5071 "1.2.840.48018.1.2.2", # MS KRB5 - Microsoft Kerberos 5 

5072 "1.2.840.113554.1.2.2", # Kerberos 5 

5073 ] 

5074 

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

5076 """ 

5077 [MS-KILE] sect 3.4.5.6 

5078 

5079 - AES: RFC4121 sect 4.2.6.1 

5080 """ 

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

5082 # Concatenate the ToSign 

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

5084 sig = KRB_InnerToken( 

5085 TOK_ID=b"\x04\x04", 

5086 root=KRB_GSS_MIC( 

5087 Flags="AcceptorSubkey" 

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

5089 SND_SEQ=Context.SendSeqNum, 

5090 ), 

5091 ) 

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

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

5094 keyusage=Context.SendSignKeyUsage, 

5095 text=ToSign, 

5096 ) 

5097 else: 

5098 raise NotImplementedError 

5099 Context.SendSeqNum += 1 

5100 return sig 

5101 

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

5103 """ 

5104 [MS-KILE] sect 3.4.5.7 

5105 

5106 - AES: RFC4121 sect 4.2.6.1 

5107 """ 

5108 Context.RecvSeqNum = signature.root.SND_SEQ 

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

5110 # Concatenate the ToSign 

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

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

5113 sig = Context.KrbSessionKey.make_checksum( 

5114 keyusage=Context.RecvSignKeyUsage, 

5115 text=ToSign, 

5116 ) 

5117 else: 

5118 raise NotImplementedError 

5119 if sig != signature.root.SGN_CKSUM: 

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

5121 

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

5123 """ 

5124 [MS-KILE] sect 3.4.5.4 

5125 

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

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

5128 """ 

5129 # Is confidentiality in use? 

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

5131 x.conf_req_flag for x in msgs 

5132 ) 

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

5134 # Build token 

5135 tok = KRB_InnerToken( 

5136 TOK_ID=b"\x05\x04", 

5137 root=KRB_GSS_Wrap( 

5138 Flags="AcceptorSubkey" 

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

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

5141 SND_SEQ=Context.SendSeqNum, 

5142 RRC=0, 

5143 ), 

5144 ) 

5145 Context.SendSeqNum += 1 

5146 # Real separation starts now: RFC4121 sect 4.2.4 

5147 if confidentiality: 

5148 # Confidentiality is requested (see RFC4121 sect 4.3) 

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

5150 # 0. Roll confounder 

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

5152 # 1. Concatenate the data to be encrypted 

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

5154 DataLen = len(Data) 

5155 # 2. Add filler 

5156 if qop_req & GSS_QOP_REQ_FLAGS.GSS_S_NO_SECBUFFER_PADDING: 

5157 # Special case for compatibility with Windows API. See 

5158 # GSS_QOP_REQ_FLAGS. 

5159 tok.root.EC = 0 

5160 else: 

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

5162 # be zero" 

5163 tok.root.EC = ( 

5164 (-DataLen) % Context.KrbSessionKey.ep.blocksize 

5165 ) or 16 

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

5167 Data += Filler 

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

5169 PlainHeader = bytes(tok)[:16] 

5170 Data += PlainHeader 

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

5172 ToSign = Confounder 

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

5174 ToSign += Filler 

5175 ToSign += PlainHeader 

5176 # 5. Finalize token for signing 

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

5178 tok.root.RRC = 28 

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

5180 # integrity protection) 

5181 Data = Context.KrbSessionKey.encrypt( 

5182 keyusage=Context.SendSealKeyUsage, 

5183 plaintext=Data, 

5184 confounder=Confounder, 

5185 signtext=ToSign, 

5186 ) 

5187 # 7. Rotate 

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

5189 # 8. Split (token and encrypted messages) 

5190 toklen = len(Data) - DataLen 

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

5192 offset = toklen 

5193 for msg in msgs: 

5194 msglen = len(msg.data) 

5195 if msg.conf_req_flag: 

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

5197 offset += msglen 

5198 return msgs, tok 

5199 else: 

5200 # No confidentiality is requested 

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

5202 # 0. Concatenate the data 

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

5204 DataLen = len(Data) 

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

5206 ToSign = Data 

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

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

5209 # checksum mechanism 

5210 Mic = Context.KrbSessionKey.make_checksum( 

5211 keyusage=Context.SendSealKeyUsage, 

5212 text=ToSign, 

5213 ) 

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

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

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

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

5218 # is requested" 

5219 tok.root.RRC = 12 

5220 # 3. Concat and pack 

5221 for msg in msgs: 

5222 if msg.sign: 

5223 msg.data = b"" 

5224 Data = Data + Mic 

5225 # 4. Rotate 

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

5227 return msgs, tok 

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

5229 # Build token 

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

5231 tok = KRB_InnerToken( 

5232 TOK_ID=b"\x02\x01", 

5233 root=KRB_GSS_Wrap_RFC1964( 

5234 SGN_ALG="HMAC", 

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

5236 SND_SEQ=seq 

5237 + ( 

5238 # See errata 

5239 b"\xff\xff\xff\xff" 

5240 if Context.IsAcceptor 

5241 else b"\x00\x00\x00\x00" 

5242 ), 

5243 ), 

5244 ) 

5245 Context.SendSeqNum += 1 

5246 # 0. Concatenate data 

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

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

5249 Kss = Context.KrbSessionKey.key 

5250 # 1. Roll confounder 

5251 Confounder = os.urandom(8) 

5252 # 2. Compute the 'Kseq' key 

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

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

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

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

5257 else: 

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

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

5260 # 3. Build SGN_CKSUM 

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

5262 keyusage=13, # See errata 

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

5264 )[:8] 

5265 # 4. Populate token + encrypt 

5266 if confidentiality: 

5267 # 'encrypt' is requested 

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

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

5270 Data = rc4.update(ToEncrypt) 

5271 # Split encrypted data 

5272 offset = 0 

5273 for msg in msgs: 

5274 msglen = len(msg.data) 

5275 if msg.conf_req_flag: 

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

5277 offset += msglen 

5278 else: 

5279 # 'encrypt' is not requested 

5280 tok.root.CONFOUNDER = Confounder 

5281 # 5. Compute the 'Kseq' key 

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

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

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

5285 else: 

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

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

5288 # 6. Encrypt 'SND_SEQ' 

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

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

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

5292 tok = KRB_GSSAPI_Token( 

5293 MechType="1.2.840.113554.1.2.2", # Kerberos 5 

5294 innerToken=tok, 

5295 ) 

5296 return msgs, tok 

5297 else: 

5298 raise NotImplementedError 

5299 

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

5301 """ 

5302 [MS-KILE] sect 3.4.5.5 

5303 

5304 - AES: RFC4121 sect 4.2.6.2 

5305 - HMAC-RC4: RFC4757 sect 7.3 

5306 """ 

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

5308 confidentiality = signature.root.Flags.Sealed 

5309 # Real separation starts now: RFC4121 sect 4.2.4 

5310 if confidentiality: 

5311 # 0. Concatenate the data 

5312 Data = signature.root.Data 

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

5314 # 1. Un-Rotate 

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

5316 

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

5318 def MakeToSign(Confounder, DecText): 

5319 offset = 0 

5320 # 2.a Confounder 

5321 ToSign = Confounder 

5322 # 2.b Messages 

5323 for msg in msgs: 

5324 msglen = len(msg.data) 

5325 if msg.conf_req_flag: 

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

5327 offset += msglen 

5328 elif msg.sign: 

5329 ToSign += msg.data 

5330 # 2.c Filler & Padding 

5331 ToSign += DecText[offset:] 

5332 return ToSign 

5333 

5334 # 3. Decrypt 

5335 Data = Context.KrbSessionKey.decrypt( 

5336 keyusage=Context.RecvSealKeyUsage, 

5337 ciphertext=Data, 

5338 presignfunc=MakeToSign, 

5339 ) 

5340 # 4. Split 

5341 Data, f16header = ( 

5342 Data[:-16], 

5343 Data[-16:], 

5344 ) 

5345 # 5. Check header 

5346 hdr = signature.copy() 

5347 hdr.root.RRC = 0 

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

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

5350 # 6. Split (and ignore filler) 

5351 offset = 0 

5352 for msg in msgs: 

5353 msglen = len(msg.data) 

5354 if msg.conf_req_flag: 

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

5356 offset += msglen 

5357 # Case without msgs 

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

5359 msgs[0].data = Data 

5360 return msgs 

5361 else: 

5362 # No confidentiality is requested 

5363 # 0. Concatenate the data 

5364 Data = signature.root.Data 

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

5366 # 1. Un-Rotate 

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

5368 # 2. Split 

5369 Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :] 

5370 # "Both the EC field and the RRC field in 

5371 # the token header SHALL be filled with zeroes for the purpose of 

5372 # calculating the checksum." 

5373 ToSign = Data 

5374 hdr = signature.copy() 

5375 hdr.root.RRC = 0 

5376 hdr.root.EC = 0 

5377 # Concatenate the data 

5378 ToSign += bytes(hdr)[:16] 

5379 # 3. Calculate the signature 

5380 sig = Context.KrbSessionKey.make_checksum( 

5381 keyusage=Context.RecvSealKeyUsage, 

5382 text=ToSign, 

5383 ) 

5384 # 4. Compare 

5385 if sig != Mic: 

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

5387 # Case without msgs 

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

5389 msgs[0].data = Data 

5390 return msgs 

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

5392 # Drop wrapping 

5393 tok = signature.innerToken 

5394 

5395 # Detect confidentiality 

5396 confidentiality = tok.root.SEAL_ALG != 0xFFFF 

5397 

5398 # 0. Concatenate data 

5399 ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

5400 Kss = Context.KrbSessionKey.key 

5401 # 1. Compute the 'Kseq' key 

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

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

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

5405 else: 

5406 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

5407 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

5408 # 2. Decrypt 'SND_SEQ' 

5409 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

5410 seq = rc4.update(tok.root.SND_SEQ)[:4] 

5411 # 3. Compute the 'Kcrypt' key 

5412 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

5413 if Context.KrbSessionKey.etype == 24: # EXP 

5414 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5415 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

5416 else: 

5417 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

5418 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

5419 # 4. Decrypt 

5420 if confidentiality: 

5421 # 'encrypt' was requested 

5422 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

5423 Confounder = rc4.update(tok.root.CONFOUNDER) 

5424 Data = rc4.update(ToDecrypt) 

5425 # Split encrypted data 

5426 offset = 0 

5427 for msg in msgs: 

5428 msglen = len(msg.data) 

5429 if msg.conf_req_flag: 

5430 msg.data = Data[offset : offset + msglen] 

5431 offset += msglen 

5432 else: 

5433 # 'encrypt' was not requested 

5434 Confounder = tok.root.CONFOUNDER 

5435 # 5. Verify SGN_CKSUM 

5436 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

5437 Context.KrbSessionKey.verify_checksum( 

5438 keyusage=13, # See errata 

5439 text=bytes(tok)[:8] + Confounder + ToSign, 

5440 cksum=tok.root.SGN_CKSUM, 

5441 ) 

5442 return msgs 

5443 else: 

5444 raise NotImplementedError 

5445 

5446 def GSS_Init_sec_context( 

5447 self, 

5448 Context: CONTEXT, 

5449 input_token=None, 

5450 target_name: Optional[str] = None, 

5451 req_flags: Optional[GSS_C_FLAGS] = None, 

5452 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5453 ): 

5454 if Context is None: 

5455 # New context 

5456 Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags) 

5457 

5458 if self.IAKERB: 

5459 # IAKERB - We return asynchronously either packets from this 

5460 # GSS_Init_sec_context, or whatever packet are wrapped when talking to 

5461 # the server. 

5462 if Context.IAKerbSocket is None: 

5463 # Initial call: create a IAKerbSocket and a thread 

5464 _, crealm = _parse_upn(self.UPN) 

5465 Context.IAKERB = True 

5466 Context.IAKerbSocket = IAKerbSocket( 

5467 Context=Context, 

5468 realm=crealm, 

5469 ) 

5470 

5471 # Run in the background 

5472 Context.IAKerbSocket.run( 

5473 self.GSS_Init_sec_context, 

5474 Context=Context, 

5475 input_token=input_token, 

5476 target_name=target_name, 

5477 req_flags=req_flags, 

5478 chan_bindings=chan_bindings, 

5479 ) 

5480 

5481 return Context.IAKerbSocket.next() 

5482 elif input_token is not None: 

5483 # Intermediate token: let the thread handle it. 

5484 iakerb = Context.IAKerbSocket.unpack(input_token) 

5485 if iakerb: 

5486 # This is a IAKERB token 

5487 return Context.IAKerbSocket.next(iakerb) 

5488 

5489 # Else, continue. This is not an IAKERB token. 

5490 

5491 if Context.state == self.STATE.INIT and self.U2U: 

5492 # U2U - Get TGT 

5493 Context.state = self.STATE.CLI_SENT_TGTREQ 

5494 return ( 

5495 Context, 

5496 KRB_GSSAPI_Token( 

5497 MechType="1.2.840.113554.1.2.2.3", # U2U 

5498 innerToken=KRB_InnerToken( 

5499 TOK_ID=b"\x04\x00", 

5500 root=KRB_TGT_REQ(), 

5501 ), 

5502 ), 

5503 GSS_S_CONTINUE_NEEDED, 

5504 ) 

5505 

5506 if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]: 

5507 if not self.UPN: 

5508 raise ValueError("Missing UPN attribute") 

5509 

5510 # Do we have a ST? 

5511 if self.ST is None: 

5512 # Client sends an AP-req 

5513 if not self.SPN and not target_name: 

5514 raise ValueError("Missing SPN/target_name attribute") 

5515 

5516 additional_tickets = [] 

5517 if self.U2U: 

5518 try: 

5519 # GSSAPI / Kerberos 

5520 tgt_rep = input_token.root.innerToken.root 

5521 except AttributeError: 

5522 try: 

5523 # Kerberos 

5524 tgt_rep = input_token.innerToken.root 

5525 except AttributeError: 

5526 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5527 if not isinstance(tgt_rep, KRB_TGT_REP): 

5528 tgt_rep.show() 

5529 raise ValueError("KerberosSSP: Unexpected input_token !") 

5530 additional_tickets = [tgt_rep.ticket] 

5531 

5532 try: 

5533 if self.TGT is None: 

5534 # Get TGT. We were passed a kerberos key 

5535 res = krb_as_req( 

5536 upn=self.UPN, 

5537 ip=self.DC_IP, 

5538 key=self.KEY, 

5539 password=self.PASSWORD, 

5540 debug=self.debug, 

5541 verbose=bool(self.debug), 

5542 iakerb=self.IAKERB, 

5543 iakerb_socket=Context.IAKerbSocket, 

5544 ) 

5545 if res is None: 

5546 # Failed to retrieve the ticket 

5547 return Context, None, GSS_S_FAILURE 

5548 

5549 # Update UPN (could have been canonicalized) 

5550 self.UPN = res.upn 

5551 

5552 # Store TGT, 

5553 self.TGT = res.asrep.ticket 

5554 self.TGTSessionKey = res.sessionkey 

5555 elif self.TGTSessionKey is None: 

5556 # We have a TGT and were passed its key 

5557 self.TGTSessionKey = self.KEY 

5558 

5559 # Get ST 

5560 if not self.TGTSessionKey: 

5561 raise ValueError("Cannot use TGT without the KEY") 

5562 

5563 res = krb_tgs_req( 

5564 upn=self.UPN, 

5565 spn=self.SPN or target_name, 

5566 ip=self.DC_IP, 

5567 sessionkey=self.TGTSessionKey, 

5568 ticket=self.TGT, 

5569 additional_tickets=additional_tickets, 

5570 u2u=self.U2U, 

5571 debug=self.debug, 

5572 verbose=bool(self.debug), 

5573 iakerb=self.IAKERB, 

5574 iakerb_socket=Context.IAKerbSocket, 

5575 ) 

5576 if not res: 

5577 # Failed to retrieve the ticket 

5578 return Context, None, GSS_S_FAILURE 

5579 except TimeoutError: 

5580 # We couldn't reach the DC to get a ticket. Fail KerberosSSP. 

5581 return Context, None, GSS_S_BAD_MECH 

5582 

5583 # Store the service ticket and associated key 

5584 Context.ST, Context.STSessionKey = res.tgsrep.ticket, res.sessionkey 

5585 elif not self.KEY: 

5586 raise ValueError("Must provide KEY with ST") 

5587 else: 

5588 # We were passed a ST and its key 

5589 Context.ST = self.ST 

5590 Context.STSessionKey = self.KEY 

5591 

5592 target_spn = self.SPN or target_name 

5593 if target_spn and not _spn_are_equal(Context.ST.getSPN(), target_spn): 

5594 raise ValueError( 

5595 "SPN from ST doesn't match the passed SPN/target_name." 

5596 ) 

5597 

5598 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5599 raise ValueError( 

5600 "Cannot use GSS_C_DELEG_FLAG when passed a service ticket !" 

5601 ) 

5602 

5603 # Save ServerHostname 

5604 if len(Context.ST.sname.nameString) == 2: 

5605 Context.ServerHostname = Context.ST.sname.nameString[1].val.decode() 

5606 

5607 # Build the KRB-AP 

5608 apOptions = ASN1_BIT_STRING("000") 

5609 if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG: 

5610 apOptions.set(2, "1") # mutual-required 

5611 if self.U2U: 

5612 apOptions.set(1, "1") # use-session-key 

5613 Context.U2U = True 

5614 ap_req = KRB_AP_REQ( 

5615 apOptions=apOptions, 

5616 ticket=Context.ST, 

5617 authenticator=EncryptedData(), 

5618 ) 

5619 

5620 # Get the current time 

5621 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5622 # Pick a random session key 

5623 Context.KrbSessionKey = Key.new_random_key( 

5624 self.SKEY_TYPE, 

5625 ) 

5626 

5627 # We use a random SendSeqNum 

5628 Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix() 

5629 

5630 # Get the realm of the client 

5631 _, crealm = _parse_upn(self.UPN) 

5632 

5633 # Build the RFC4121 authenticator checksum 

5634 authenticator_checksum = KRB_AuthenticatorChecksum( 

5635 # RFC 4121 sect 4.1.1.2 

5636 # "The Bnd field contains the MD5 hash of channel bindings" 

5637 Bnd=( 

5638 chan_bindings.digestMD5() 

5639 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5640 else (b"\x00" * 16) 

5641 ), 

5642 Flags=int(Context.flags), 

5643 ) 

5644 

5645 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5646 # Delegate TGT 

5647 raise NotImplementedError("GSS_C_DELEG_FLAG is not implemented !") 

5648 # authenticator_checksum.Deleg = KRB_CRED( 

5649 # tickets=[self.TGT], 

5650 # encPart=EncryptedData() 

5651 # ) 

5652 # authenticator_checksum.encPart.encrypt( 

5653 # Context.STSessionKey, 

5654 # EncKrbCredPart( 

5655 # ticketInfo=KrbCredInfo( 

5656 # key=EncryptionKey.fromKey(self.TGTSessionKey), 

5657 # prealm=ASN1_GENERAL_STRING(crealm), 

5658 # pname=PrincipalName.fromUPN(self.UPN), 

5659 # # TODO: rework API to pass starttime... here. 

5660 # sreralm=self.TGT.realm, 

5661 # sname=self.TGT.sname, 

5662 # ) 

5663 # ) 

5664 # ) 

5665 

5666 # Build and encrypt the full KRB_Authenticator 

5667 ap_req.authenticator.encrypt( 

5668 Context.STSessionKey, 

5669 KRB_Authenticator( 

5670 crealm=crealm, 

5671 cname=PrincipalName.fromUPN(self.UPN), 

5672 cksum=Checksum( 

5673 cksumtype="KRB-AUTHENTICATOR", checksum=authenticator_checksum 

5674 ), 

5675 ctime=ASN1_GENERALIZED_TIME(now_time), 

5676 cusec=ASN1_INTEGER(0), 

5677 subkey=EncryptionKey.fromKey(Context.KrbSessionKey), 

5678 seqNumber=Context.SendSeqNum, 

5679 encAuthorizationData=AuthorizationData( 

5680 seq=[ 

5681 AuthorizationDataItem( 

5682 adType="AD-IF-RELEVANT", 

5683 adData=AuthorizationData( 

5684 seq=[ 

5685 AuthorizationDataItem( 

5686 adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

5687 adData=KERB_AD_RESTRICTION_ENTRY( 

5688 restriction=LSAP_TOKEN_INFO_INTEGRITY( 

5689 MachineID=bytes(RandBin(32)), 

5690 PermanentMachineID=bytes( 

5691 RandBin(32) 

5692 ), 

5693 ) 

5694 ), 

5695 ), 

5696 # This isn't documented, but sent on Windows :/ 

5697 AuthorizationDataItem( 

5698 adType="KERB-LOCAL", 

5699 adData=b"\x00" * 16, 

5700 ), 

5701 ] 

5702 + ( 

5703 # Channel bindings 

5704 [ 

5705 AuthorizationDataItem( 

5706 adType="AD-AUTH-DATA-AP-OPTIONS", 

5707 adData=KERB_AUTH_DATA_AP_OPTIONS( 

5708 apOptions="KERB_AP_OPTIONS_CBT" 

5709 ), 

5710 ) 

5711 ] 

5712 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5713 else [] 

5714 ) 

5715 ), 

5716 ) 

5717 ] 

5718 ), 

5719 ), 

5720 ) 

5721 Context.state = self.STATE.CLI_SENT_APREQ 

5722 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5723 # Raw kerberos DCE-STYLE 

5724 return Context, ap_req, GSS_S_CONTINUE_NEEDED 

5725 else: 

5726 # Kerberos wrapper 

5727 return ( 

5728 Context, 

5729 KRB_GSSAPI_Token( 

5730 innerToken=KRB_InnerToken( 

5731 root=ap_req, 

5732 ) 

5733 ), 

5734 GSS_S_CONTINUE_NEEDED, 

5735 ) 

5736 

5737 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5738 if isinstance(input_token, KRB_AP_REP): 

5739 # Raw AP_REP was passed 

5740 ap_rep = input_token 

5741 else: 

5742 try: 

5743 # GSSAPI / Kerberos 

5744 ap_rep = input_token.root.innerToken.root 

5745 except AttributeError: 

5746 try: 

5747 # Kerberos 

5748 ap_rep = input_token.innerToken.root 

5749 except AttributeError: 

5750 try: 

5751 # Raw kerberos DCE-STYLE 

5752 ap_rep = input_token.root 

5753 except AttributeError: 

5754 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5755 if not isinstance(ap_rep, KRB_AP_REP): 

5756 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5757 

5758 # Retrieve SessionKey 

5759 repPart = ap_rep.encPart.decrypt(Context.STSessionKey) 

5760 if repPart.subkey is not None: 

5761 Context.SessionKey = repPart.subkey.keyvalue.val 

5762 Context.KrbSessionKey = repPart.subkey.toKey() 

5763 

5764 # OK ! 

5765 Context.state = self.STATE.CLI_RCVD_APREP 

5766 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5767 # [MS-KILE] sect 3.4.5.1 

5768 # The client MUST generate an additional AP exchange reply message 

5769 # exactly as the server would as the final message to send to the 

5770 # server. 

5771 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5772 cli_ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5773 cli_ap_rep.encPart.encrypt( 

5774 Context.STSessionKey, 

5775 EncAPRepPart( 

5776 ctime=ASN1_GENERALIZED_TIME(now_time), 

5777 seqNumber=repPart.seqNumber, 

5778 subkey=None, 

5779 ), 

5780 ) 

5781 return Context, cli_ap_rep, GSS_S_COMPLETE 

5782 return Context, None, GSS_S_COMPLETE 

5783 elif ( 

5784 Context.state == self.STATE.CLI_RCVD_APREP 

5785 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5786 ): 

5787 # DCE_STYLE with SPNEGOSSP 

5788 return Context, None, GSS_S_COMPLETE 

5789 else: 

5790 raise ValueError("KerberosSSP: Unknown state") 

5791 

5792 def GSS_Accept_sec_context( 

5793 self, 

5794 Context: CONTEXT, 

5795 input_token=None, 

5796 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5797 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5798 ): 

5799 if Context is None: 

5800 # New context 

5801 Context = self.CONTEXT(IsAcceptor=True, req_flags=req_flags) 

5802 

5803 import scapy.layers.msrpce.mspac # noqa: F401 

5804 

5805 if Context.state == self.STATE.INIT: 

5806 if self.UPN and self.SPN: 

5807 raise ValueError("Cannot use SPN and UPN at the same time !") 

5808 if self.SPN and self.TGT: 

5809 raise ValueError("Cannot use TGT with SPN.") 

5810 if self.UPN and not self.TGT: 

5811 # UPN is provided: use U2U 

5812 res = krb_as_req( 

5813 self.UPN, 

5814 self.DC_IP, 

5815 key=self.KEY, 

5816 password=self.PASSWORD, 

5817 ) 

5818 self.TGT, self.TGTSessionKey = res.asrep.ticket, res.sessionkey 

5819 

5820 # Server receives AP-req, sends AP-rep 

5821 if isinstance(input_token, KRB_AP_REQ): 

5822 # Raw AP_REQ was passed 

5823 ap_req = input_token 

5824 else: 

5825 try: 

5826 # GSSAPI/Kerberos 

5827 ap_req = input_token.root.innerToken.root 

5828 except AttributeError: 

5829 try: 

5830 # Kerberos 

5831 ap_req = input_token.innerToken.root 

5832 except AttributeError: 

5833 try: 

5834 # Raw kerberos 

5835 ap_req = input_token.root 

5836 except AttributeError: 

5837 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5838 

5839 if isinstance(ap_req, KRB_TGT_REQ): 

5840 # Special U2U case 

5841 Context.U2U = True 

5842 return ( 

5843 None, 

5844 KRB_GSSAPI_Token( 

5845 MechType="1.2.840.113554.1.2.2.3", # U2U 

5846 innerToken=KRB_InnerToken( 

5847 TOK_ID=b"\x04\x01", 

5848 root=KRB_TGT_REP( 

5849 ticket=self.TGT, 

5850 ), 

5851 ), 

5852 ), 

5853 GSS_S_CONTINUE_NEEDED, 

5854 ) 

5855 elif not isinstance(ap_req, KRB_AP_REQ): 

5856 ap_req.show() 

5857 raise ValueError("Unexpected type in KerberosSSP") 

5858 if not self.KEY: 

5859 raise ValueError("Missing KEY attribute") 

5860 

5861 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5862 

5863 # If using a UPN, require U2U 

5864 if self.UPN and ap_req.apOptions.val[1] != "1": # use-session-key 

5865 # Required but not provided. Return an error 

5866 Context.U2U = True 

5867 err = KRB_GSSAPI_Token( 

5868 innerToken=KRB_InnerToken( 

5869 TOK_ID=b"\x03\x00", 

5870 root=KRB_ERROR( 

5871 errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED", 

5872 stime=ASN1_GENERALIZED_TIME(now_time), 

5873 realm=ap_req.ticket.realm, 

5874 sname=ap_req.ticket.sname, 

5875 eData=KRB_TGT_REP( 

5876 ticket=self.TGT, 

5877 ), 

5878 ), 

5879 ) 

5880 ) 

5881 return Context, err, GSS_S_CONTINUE_NEEDED 

5882 

5883 # Validate the 'serverName' of the ticket. 

5884 sname = ap_req.ticket.getSPN() 

5885 our_sname = self.SPN or self.UPN 

5886 if not _spn_are_equal(our_sname, sname): 

5887 warning("KerberosSSP: bad server name: %s != %s" % (sname, our_sname)) 

5888 err = KRB_GSSAPI_Token( 

5889 innerToken=KRB_InnerToken( 

5890 TOK_ID=b"\x03\x00", 

5891 root=KRB_ERROR( 

5892 errorCode="KRB_AP_ERR_BADMATCH", 

5893 stime=ASN1_GENERALIZED_TIME(now_time), 

5894 realm=ap_req.ticket.realm, 

5895 sname=ap_req.ticket.sname, 

5896 eData=None, 

5897 ), 

5898 ) 

5899 ) 

5900 return Context, err, GSS_S_BAD_MECH 

5901 

5902 # Decrypt the ticket 

5903 try: 

5904 tkt = ap_req.ticket.encPart.decrypt(self.KEY) 

5905 except ValueError as ex: 

5906 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5907 err = KRB_GSSAPI_Token( 

5908 innerToken=KRB_InnerToken( 

5909 TOK_ID=b"\x03\x00", 

5910 root=KRB_ERROR( 

5911 errorCode="KRB_AP_ERR_MODIFIED", 

5912 stime=ASN1_GENERALIZED_TIME(now_time), 

5913 realm=ap_req.ticket.realm, 

5914 sname=ap_req.ticket.sname, 

5915 eData=None, 

5916 ), 

5917 ) 

5918 ) 

5919 return Context, err, GSS_S_DEFECTIVE_CREDENTIAL 

5920 

5921 # Store information about the user in the Context 

5922 if tkt.authorizationData and tkt.authorizationData.seq: 

5923 # Get AD-IF-RELEVANT 

5924 adIfRelevant = tkt.authorizationData.getAuthData(0x1) 

5925 if adIfRelevant: 

5926 # Get AD-WIN2K-PAC 

5927 Context.PAC = adIfRelevant.getAuthData(0x80) 

5928 

5929 # Get AP-REQ session key 

5930 Context.STSessionKey = tkt.key.toKey() 

5931 authenticator = ap_req.authenticator.decrypt(Context.STSessionKey) 

5932 

5933 # Compute an application session key ([MS-KILE] sect 3.1.1.2) 

5934 subkey = None 

5935 if ap_req.apOptions.val[2] == "1": # mutual-required 

5936 appkey = Key.new_random_key( 

5937 self.SKEY_TYPE, 

5938 ) 

5939 Context.KrbSessionKey = appkey 

5940 Context.SessionKey = appkey.key 

5941 subkey = EncryptionKey.fromKey(appkey) 

5942 else: 

5943 Context.KrbSessionKey = self.KEY 

5944 Context.SessionKey = self.KEY.key 

5945 

5946 # Eventually process the "checksum" 

5947 if authenticator.cksum and authenticator.cksum.cksumtype == 0x8003: 

5948 # KRB-Authenticator 

5949 authcksum = authenticator.cksum.checksum 

5950 Context.flags = authcksum.Flags 

5951 # Check channel bindings 

5952 if ( 

5953 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5954 and chan_bindings.digestMD5() != authcksum.Bnd 

5955 and not ( 

5956 GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS in req_flags 

5957 and authcksum.Bnd == GSS_C_NO_CHANNEL_BINDINGS 

5958 ) 

5959 ): 

5960 # Channel binding checks failed. 

5961 return Context, None, GSS_S_BAD_BINDINGS 

5962 elif ( 

5963 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5964 and GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS not in req_flags 

5965 ): 

5966 # Uhoh, we required channel bindings 

5967 return Context, None, GSS_S_BAD_BINDINGS 

5968 

5969 # Build response (RFC4120 sect 3.2.4) 

5970 ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5971 ap_rep.encPart.encrypt( 

5972 Context.STSessionKey, 

5973 EncAPRepPart( 

5974 ctime=authenticator.ctime, 

5975 cusec=authenticator.cusec, 

5976 seqNumber=None, 

5977 subkey=subkey, 

5978 ), 

5979 ) 

5980 Context.state = self.STATE.SRV_SENT_APREP 

5981 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5982 # [MS-KILE] sect 3.4.5.1 

5983 return Context, ap_rep, GSS_S_CONTINUE_NEEDED 

5984 return Context, ap_rep, GSS_S_COMPLETE # success 

5985 elif ( 

5986 Context.state == self.STATE.SRV_SENT_APREP 

5987 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5988 ): 

5989 # [MS-KILE] sect 3.4.5.1 

5990 # The server MUST receive the additional AP exchange reply message and 

5991 # verify that the message is constructed correctly. 

5992 if not input_token: 

5993 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5994 # Server receives AP-req, sends AP-rep 

5995 if isinstance(input_token, KRB_AP_REP): 

5996 # Raw AP_REP was passed 

5997 ap_rep = input_token 

5998 else: 

5999 try: 

6000 # GSSAPI/Kerberos 

6001 ap_rep = input_token.root.innerToken.root 

6002 except AttributeError: 

6003 try: 

6004 # Raw Kerberos 

6005 ap_rep = input_token.root 

6006 except AttributeError: 

6007 return Context, None, GSS_S_DEFECTIVE_TOKEN 

6008 # Decrypt the AP-REP 

6009 try: 

6010 ap_rep.encPart.decrypt(Context.STSessionKey) 

6011 except ValueError as ex: 

6012 warning("KerberosSSP: %s (bad KEY?)" % ex) 

6013 return Context, None, GSS_S_DEFECTIVE_TOKEN 

6014 return Context, None, GSS_S_COMPLETE # success 

6015 else: 

6016 raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state)) 

6017 

6018 def GSS_Passive( 

6019 self, 

6020 Context: CONTEXT, 

6021 input_token=None, 

6022 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

6023 ): 

6024 if Context is None: 

6025 Context = self.CONTEXT(True) 

6026 Context.passive = True 

6027 

6028 if Context.state == self.STATE.INIT or ( 

6029 # In DCE/RPC, there's an extra AP-REP sent from the client. 

6030 Context.state == self.STATE.SRV_SENT_APREP 

6031 and req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

6032 ): 

6033 Context, _, status = self.GSS_Accept_sec_context( 

6034 Context, 

6035 input_token=input_token, 

6036 req_flags=req_flags, 

6037 ) 

6038 if status in [GSS_S_CONTINUE_NEEDED, GSS_S_COMPLETE]: 

6039 Context.state = self.STATE.CLI_SENT_APREQ 

6040 else: 

6041 Context.state = self.STATE.FAILED 

6042 elif Context.state == self.STATE.CLI_SENT_APREQ: 

6043 Context, _, status = self.GSS_Init_sec_context( 

6044 Context, 

6045 input_token=input_token, 

6046 req_flags=req_flags, 

6047 ) 

6048 if status == GSS_S_COMPLETE: 

6049 if req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

6050 status = GSS_S_CONTINUE_NEEDED 

6051 Context.state = self.STATE.SRV_SENT_APREP 

6052 else: 

6053 Context.state == self.STATE.FAILED 

6054 else: 

6055 # Unknown state. Don't crash though. 

6056 status = GSS_S_FAILURE 

6057 

6058 return Context, status 

6059 

6060 def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False): 

6061 if Context.IsAcceptor is not IsAcceptor: 

6062 return 

6063 # Swap everything 

6064 Context.SendSealKeyUsage, Context.RecvSealKeyUsage = ( 

6065 Context.RecvSealKeyUsage, 

6066 Context.SendSealKeyUsage, 

6067 ) 

6068 Context.SendSignKeyUsage, Context.RecvSignKeyUsage = ( 

6069 Context.RecvSignKeyUsage, 

6070 Context.SendSignKeyUsage, 

6071 ) 

6072 Context.IsAcceptor = not Context.IsAcceptor 

6073 

6074 def LegsAmount(self, Context: CONTEXT): 

6075 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

6076 return 4 

6077 else: 

6078 return 2 

6079 

6080 def MaximumSignatureLength(self, Context: CONTEXT): 

6081 if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG: 

6082 # TODO: support DES 

6083 if Context.KrbSessionKey.etype in [17, 18]: # AES 

6084 return 76 

6085 elif Context.KrbSessionKey.etype in [23, 24]: # RC4_HMAC 

6086 return 45 

6087 else: 

6088 raise NotImplementedError 

6089 else: 

6090 return 28