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

1796 statements  

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

2# This file is part of Scapy 

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

4# Copyright (C) Gabriel Potter 

5 

6r""" 

7Kerberos V5 

8 

9Implements parts of: 

10 

11- Kerberos Network Authentication Service (V5): RFC4120 

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

13- Kerberos Pre-Authentication: RFC6113 (FAST) 

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

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

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

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

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

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

20 draft-ietf-kitten-iakerb-03 

21- Kerberos Protocol Extensions: [MS-KILE] 

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

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

24 

25 

26.. note:: 

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

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

29 

30Example decryption:: 

31 

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

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

34 83c0a87a9cc0a87a11c209005854f6ab2392c25bd650182014b6e00000000001316a8201\ 

35 2d30820129a103020105a20302010aa3633061304ca103020102a24504433041a0030201\ 

36 12a23a043848484decb01c9b62a1cabfbc3f2d1ed85aa5e093ba8358a8cea34d4393af93\ 

37 bf211e274fa58e814878db9f0d7a28d94e7327660db4f3704b3011a10402020080a20904\ 

38 073005a0030101ffa481b73081b4a00703050040810010a1123010a003020101a1093007\ 

39 1b0577696e3124a20e1b0c444f4d41494e2e4c4f43414ca321301fa003020102a1183016\ 

40 1b066b72627467741b0c444f4d41494e2e4c4f43414ca511180f32303337303931333032\ 

41 343830355aa611180f32303337303931333032343830355aa7060204701cc5d1a8153013\ 

42 0201120201110201170201180202ff79020103a91d301b3019a003020114a11204105749\ 

43 4e31202020202020202020202020")) 

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

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

46 e87127a819d42e69b5e22de0ddc63da80096d")) 

47 >>> enc.decrypt(k) 

48""" 

49 

50from collections import namedtuple, deque 

51from datetime import datetime, timedelta, timezone 

52from enum import IntEnum 

53 

54import os 

55import re 

56import socket 

57import struct 

58 

59from scapy.error import warning 

60import scapy.asn1.mib # noqa: F401 

61from scapy.asn1.ber import BER_id_dec, BER_Decoding_Error 

62from scapy.asn1.asn1 import ( 

63 ASN1_BIT_STRING, 

64 ASN1_BOOLEAN, 

65 ASN1_Class, 

66 ASN1_Codecs, 

67 ASN1_GENERAL_STRING, 

68 ASN1_GENERALIZED_TIME, 

69 ASN1_INTEGER, 

70 ASN1_OID, 

71 ASN1_STRING, 

72) 

73from scapy.asn1fields import ( 

74 ASN1F_BIT_STRING_ENCAPS, 

75 ASN1F_BOOLEAN, 

76 ASN1F_CHOICE, 

77 ASN1F_enum_INTEGER, 

78 ASN1F_FLAGS, 

79 ASN1F_GENERAL_STRING, 

80 ASN1F_GENERALIZED_TIME, 

81 ASN1F_INTEGER, 

82 ASN1F_OID, 

83 ASN1F_optional, 

84 ASN1F_PACKET, 

85 ASN1F_SEQUENCE_OF, 

86 ASN1F_SEQUENCE, 

87 ASN1F_STRING_ENCAPS, 

88 ASN1F_STRING_PacketField, 

89 ASN1F_STRING, 

90) 

91from scapy.asn1packet import ASN1_Packet 

92from scapy.automaton import Automaton, ATMT 

93from scapy.config import conf 

94from scapy.compat import bytes_encode 

95from scapy.error import log_runtime 

96from scapy.fields import ( 

97 ConditionalField, 

98 FieldLenField, 

99 FlagsField, 

100 IntEnumField, 

101 LEIntEnumField, 

102 LenField, 

103 LEShortEnumField, 

104 LEShortField, 

105 LongField, 

106 MayEnd, 

107 MultipleTypeField, 

108 PacketField, 

109 PacketLenField, 

110 PacketListField, 

111 PadField, 

112 ShortEnumField, 

113 ShortField, 

114 StrField, 

115 StrFieldUtf16, 

116 StrFixedLenEnumField, 

117 XByteField, 

118 XLEIntEnumField, 

119 XLEIntField, 

120 XLEShortField, 

121 XStrField, 

122 XStrFixedLenField, 

123 XStrLenField, 

124) 

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

126from scapy.supersocket import StreamSocket, SuperSocket 

127from scapy.utils import strrot, strxor 

128from scapy.volatile import GeneralizedTime, RandNum, RandBin 

129 

130from scapy.layers.gssapi import ( 

131 _GSSAPI_OIDS, 

132 _GSSAPI_SIGNATURE_OIDS, 

133 GSS_C_FLAGS, 

134 GSS_C_NO_CHANNEL_BINDINGS, 

135 GSS_QOP_REQ_FLAGS, 

136 GSS_S_BAD_BINDINGS, 

137 GSS_S_BAD_MECH, 

138 GSS_S_COMPLETE, 

139 GSS_S_CONTINUE_NEEDED, 

140 GSS_S_DEFECTIVE_CREDENTIAL, 

141 GSS_S_DEFECTIVE_TOKEN, 

142 GSS_S_FAILURE, 

143 GSS_S_FLAGS, 

144 GSSAPI_BLOB, 

145 GssChannelBindings, 

146 SSP, 

147) 

148from scapy.layers.inet import TCP, UDP 

149from scapy.layers.smb import _NV_VERSION 

150from scapy.layers.tls.cert import ( 

151 Cert, 

152 CertList, 

153 CertTree, 

154 CMS_Engine, 

155 PrivKey, 

156) 

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

158 Hash_SHA, 

159 Hash_SHA256, 

160 Hash_SHA384, 

161 Hash_SHA512, 

162) 

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

164from scapy.layers.windows.erref import STATUS_ERREF 

165from scapy.layers.x509 import ( 

166 _CMS_ENCAPSULATED, 

167 CMS_ContentInfo, 

168 CMS_IssuerAndSerialNumber, 

169 DHPublicKey, 

170 X509_AlgorithmIdentifier, 

171 X509_DirectoryName, 

172 X509_SubjectPublicKeyInfo, 

173 DomainParameters, 

174) 

175 

176# Redirect exports from RFC3961 

177try: 

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

179 from scapy.libs.rfc3961 import ( 

180 _rfc1964pad, 

181 ChecksumType, 

182 Cipher, 

183 decrepit_algorithms, 

184 EncryptionType, 

185 Hmac_MD5, 

186 Key, 

187 KRB_FX_CF2, 

188 octetstring2key, 

189 ) 

190except ImportError: 

191 pass 

192 

193 

194# Crypto imports 

195if conf.crypto_valid: 

196 from cryptography.hazmat.primitives.serialization import pkcs12 

197 from cryptography.hazmat.primitives.asymmetric import dh 

198 

199# Typing imports 

200from typing import ( 

201 List, 

202 Optional, 

203 Union, 

204) 

205 

206# kerberos APPLICATION 

207 

208 

209class ASN1_Class_KRB(ASN1_Class): 

210 name = "Kerberos" 

211 # APPLICATION + CONSTRUCTED = 0x40 | 0x20 

212 Token = 0x60 | 0 # GSSAPI 

213 Ticket = 0x60 | 1 

214 Authenticator = 0x60 | 2 

215 EncTicketPart = 0x60 | 3 

216 AS_REQ = 0x60 | 10 

217 AS_REP = 0x60 | 11 

218 TGS_REQ = 0x60 | 12 

219 TGS_REP = 0x60 | 13 

220 AP_REQ = 0x60 | 14 

221 AP_REP = 0x60 | 15 

222 PRIV = 0x60 | 21 

223 CRED = 0x60 | 22 

224 EncASRepPart = 0x60 | 25 

225 EncTGSRepPart = 0x60 | 26 

226 EncAPRepPart = 0x60 | 27 

227 EncKrbPrivPart = 0x60 | 28 

228 EncKrbCredPart = 0x60 | 29 

229 ERROR = 0x60 | 30 

230 

231 

232# RFC4120 sect 5.2 

233 

234 

235KerberosString = ASN1F_GENERAL_STRING 

236Realm = KerberosString 

237Int32 = ASN1F_INTEGER 

238UInt32 = ASN1F_INTEGER 

239 

240_PRINCIPAL_NAME_TYPES = { 

241 0: "NT-UNKNOWN", 

242 1: "NT-PRINCIPAL", 

243 2: "NT-SRV-INST", 

244 3: "NT-SRV-HST", 

245 4: "NT-SRV-XHST", 

246 5: "NT-UID", 

247 6: "NT-X500-PRINCIPAL", 

248 7: "NT-SMTP-NAME", 

249 10: "NT-ENTERPRISE", 

250} 

251 

252 

253class PrincipalName(ASN1_Packet): 

254 ASN1_codec = ASN1_Codecs.BER 

255 ASN1_root = ASN1F_SEQUENCE( 

256 ASN1F_enum_INTEGER( 

257 "nameType", 

258 0, 

259 _PRINCIPAL_NAME_TYPES, 

260 explicit_tag=0xA0, 

261 ), 

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

263 ) 

264 

265 def toString(self): 

266 """ 

267 Convert a PrincipalName back into its string representation. 

268 """ 

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

270 

271 @staticmethod 

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

273 """ 

274 Create a PrincipalName from a UPN string. 

275 """ 

276 if canonicalize: 

277 return PrincipalName( 

278 nameString=[ASN1_GENERAL_STRING(upn)], 

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

280 ) 

281 else: 

282 user, _ = _parse_upn(upn) 

283 return PrincipalName( 

284 nameString=[ASN1_GENERAL_STRING(user)], 

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

286 ) 

287 

288 @staticmethod 

289 def fromSPN(spn: str): 

290 """ 

291 Create a PrincipalName from a SPN string. 

292 """ 

293 spn, _ = _parse_spn(spn) 

294 if spn.startswith("krbtgt"): 

295 return PrincipalName( 

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

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

298 ) 

299 elif "/" in spn: 

300 return PrincipalName( 

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

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

303 ) 

304 else: 

305 # In case of U2U 

306 return PrincipalName( 

307 nameString=[ASN1_GENERAL_STRING(spn)], 

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

309 ) 

310 

311 

312KerberosTime = ASN1F_GENERALIZED_TIME 

313Microseconds = ASN1F_INTEGER 

314 

315 

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

317 

318_KRB_E_TYPES = { 

319 1: "DES-CBC-CRC", 

320 2: "DES-CBC-MD4", 

321 3: "DES-CBC-MD5", 

322 5: "DES3-CBC-MD5", 

323 7: "DES3-CBC-SHA1", 

324 9: "DSAWITHSHA1-CMSOID", 

325 10: "MD5WITHRSAENCRYPTION-CMSOID", 

326 11: "SHA1WITHRSAENCRYPTION-CMSOID", 

327 12: "RC2CBC-ENVOID", 

328 13: "RSAENCRYPTION-ENVOID", 

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

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

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

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

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

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

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

336 23: "RC4-HMAC", 

337 24: "RC4-HMAC-EXP", 

338 25: "CAMELLIA128-CTS-CMAC", 

339 26: "CAMELLIA256-CTS-CMAC", 

340} 

341 

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

343 

344_KRB_S_TYPES = { 

345 1: "CRC32", 

346 2: "RSA-MD4", 

347 3: "RSA-MD4-DES", 

348 4: "DES-MAC", 

349 5: "DES-MAC-K", 

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

351 7: "RSA-MD5", 

352 8: "RSA-MD5-DES", 

353 9: "RSA-MD5-DES3", 

354 10: "SHA1", 

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

356 13: "HMAC-SHA1-DES3", 

357 14: "SHA1", 

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

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

360 17: "CMAC-CAMELLIA128", 

361 18: "CMAC-CAMELLIA256", 

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

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

364 # RFC 4121 

365 0x8003: "KRB-AUTHENTICATOR", 

366 # [MS-KILE] 

367 0xFFFFFF76: "MD5", 

368 -138: "MD5", 

369} 

370 

371 

372class EncryptedData(ASN1_Packet): 

373 ASN1_codec = ASN1_Codecs.BER 

374 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

378 ) 

379 

380 def get_usage(self): 

381 """ 

382 Get current key usage number and encrypted class 

383 """ 

384 # RFC 4120 sect 7.5.1 

385 if self.underlayer: 

386 if isinstance(self.underlayer, PADATA): 

387 patype = self.underlayer.padataType 

388 if patype == 2: 

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

390 return 1, PA_ENC_TS_ENC 

391 elif patype == 138: 

392 # RFC6113 PA-ENC-TS-ENC 

393 return 54, PA_ENC_TS_ENC 

394 elif isinstance(self.underlayer, KRB_Ticket): 

395 # AS-REP Ticket and TGS-REP Ticket 

396 return 2, EncTicketPart 

397 elif isinstance(self.underlayer, KRB_AS_REP): 

398 # AS-REP encrypted part 

399 return 3, EncASRepPart 

400 elif isinstance(self.underlayer, KRB_KDC_REQ_BODY): 

401 # KDC-REQ enc-authorization-data 

402 return 4, AuthorizationData 

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

404 self.underlayer.underlayer, PADATA 

405 ): 

406 # TGS-REQ PA-TGS-REQ Authenticator 

407 return 7, KRB_Authenticator 

408 elif isinstance(self.underlayer, KRB_TGS_REP): 

409 # TGS-REP encrypted part 

410 return 8, EncTGSRepPart 

411 elif isinstance(self.underlayer, KRB_AP_REQ): 

412 # AP-REQ Authenticator 

413 return 11, KRB_Authenticator 

414 elif isinstance(self.underlayer, KRB_AP_REP): 

415 # AP-REP encrypted part 

416 return 12, EncAPRepPart 

417 elif isinstance(self.underlayer, KRB_PRIV): 

418 # KRB-PRIV encrypted part 

419 return 13, EncKrbPrivPart 

420 elif isinstance(self.underlayer, KRB_CRED): 

421 # KRB-CRED encrypted part 

422 return 14, EncKrbCredPart 

423 elif isinstance(self.underlayer, KrbFastArmoredReq): 

424 # KEY_USAGE_FAST_ENC 

425 return 51, KrbFastReq 

426 elif isinstance(self.underlayer, KrbFastArmoredRep): 

427 # KEY_USAGE_FAST_REP 

428 return 52, KrbFastResponse 

429 raise ValueError( 

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

431 ) 

432 

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

434 """ 

435 Decrypt and return the data contained in cipher. 

436 

437 :param key: the key to use for decryption 

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

439 Guessed otherwise 

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

441 Guessed otherwise (or bytes) 

442 """ 

443 if key_usage_number is None: 

444 key_usage_number, cls = self.get_usage() 

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

446 if cls: 

447 try: 

448 return cls(d) 

449 except BER_Decoding_Error: 

450 if cls == EncASRepPart: 

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

452 # "Compatibility note: Some implementations unconditionally send an 

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

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

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

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

457 try: 

458 res = EncTGSRepPart(d) 

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

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

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

462 log_runtime.warning( 

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

464 ) 

465 return res 

466 except BER_Decoding_Error: 

467 pass 

468 raise 

469 return d 

470 

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

472 """ 

473 Encrypt text and set it into cipher. 

474 

475 :param key: the key to use for encryption 

476 :param text: the bytes value to encode 

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

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

479 Guessed otherwise 

480 """ 

481 if key_usage_number is None: 

482 key_usage_number = self.get_usage()[0] 

483 self.etype = key.etype 

484 self.cipher = ASN1_STRING( 

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

486 ) 

487 

488 

489class EncryptionKey(ASN1_Packet): 

490 ASN1_codec = ASN1_Codecs.BER 

491 ASN1_root = ASN1F_SEQUENCE( 

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

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

494 ) 

495 

496 def toKey(self): 

497 return Key( 

498 etype=self.keytype.val, 

499 key=self.keyvalue.val, 

500 ) 

501 

502 @classmethod 

503 def fromKey(self, key): 

504 return EncryptionKey( 

505 keytype=key.etype, 

506 keyvalue=key.key, 

507 ) 

508 

509 

510class _Checksum_Field(ASN1F_STRING_PacketField): 

511 def m2i(self, pkt, s): 

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

513 if not val[0].val: 

514 return val 

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

516 # Special case per RFC 4121 

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

518 return val 

519 

520 

521class Checksum(ASN1_Packet): 

522 ASN1_codec = ASN1_Codecs.BER 

523 ASN1_root = ASN1F_SEQUENCE( 

524 ASN1F_enum_INTEGER( 

525 "cksumtype", 

526 0, 

527 _KRB_S_TYPES, 

528 explicit_tag=0xA0, 

529 ), 

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

531 ) 

532 

533 def get_usage(self): 

534 """ 

535 Get current key usage number 

536 """ 

537 # RFC 4120 sect 7.5.1 

538 if self.underlayer: 

539 if isinstance(self.underlayer, KRB_Authenticator): 

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

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

542 return 6 

543 elif isinstance(self.underlayer, PA_FOR_USER): 

544 # [MS-SFU] sect 2.2.1 

545 return 17 

546 elif isinstance(self.underlayer, PA_S4U_X509_USER): 

547 # [MS-SFU] sect 2.2.2 

548 return 26 

549 elif isinstance(self.underlayer, AD_KDCIssued): 

550 # AD-KDC-ISSUED checksum 

551 return 19 

552 elif isinstance(self.underlayer, KrbFastArmoredReq): 

553 # KEY_USAGE_FAST_REQ_CHKSUM 

554 return 50 

555 elif isinstance(self.underlayer, KrbFastFinished): 

556 # KEY_USAGE_FAST_FINISHED 

557 return 53 

558 raise ValueError( 

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

560 ) 

561 

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

563 """ 

564 Verify a signature of text using a key. 

565 

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

567 :param text: the bytes to verify 

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

569 Guessed otherwise 

570 """ 

571 if key_usage_number is None: 

572 key_usage_number = self.get_usage() 

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

574 

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

576 """ 

577 Make a signature. 

578 

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

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

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

582 Guessed otherwise 

583 """ 

584 if key_usage_number is None: 

585 key_usage_number = self.get_usage() 

586 self.cksumtype = cksumtype or key.cksumtype 

587 self.checksum = ASN1_STRING( 

588 key.make_checksum( 

589 keyusage=key_usage_number, 

590 text=text, 

591 cksumtype=self.cksumtype, 

592 ) 

593 ) 

594 

595 

596KerberosFlags = ASN1F_FLAGS 

597 

598_ADDR_TYPES = { 

599 # RFC4120 sect 7.5.3 

600 0x02: "IPv4", 

601 0x03: "Directional", 

602 0x05: "ChaosNet", 

603 0x06: "XNS", 

604 0x07: "ISO", 

605 0x0C: "DECNET Phase IV", 

606 0x10: "AppleTalk DDP", 

607 0x14: "NetBios", 

608 0x18: "IPv6", 

609} 

610 

611 

612class HostAddress(ASN1_Packet): 

613 ASN1_codec = ASN1_Codecs.BER 

614 ASN1_root = ASN1F_SEQUENCE( 

615 ASN1F_enum_INTEGER( 

616 "addrType", 

617 0, 

618 _ADDR_TYPES, 

619 explicit_tag=0xA0, 

620 ), 

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

622 ) 

623 

624 

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

626 name, [], HostAddress, **kwargs 

627) 

628 

629 

630_AUTHORIZATIONDATA_VALUES = { 

631 # Filled below 

632} 

633 

634 

635class _AuthorizationData_value_Field(ASN1F_STRING_PacketField): 

636 def m2i(self, pkt, s): 

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

638 if not val[0].val: 

639 return val 

640 if pkt.adType.val in _AUTHORIZATIONDATA_VALUES: 

641 return ( 

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

643 val[1], 

644 ) 

645 return val 

646 

647 

648_AD_TYPES = { 

649 # RFC4120 sect 7.5.4 

650 1: "AD-IF-RELEVANT", 

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

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

653 4: "AD-KDC-ISSUED", 

654 5: "AD-AND-OR", 

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

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

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

658 64: "OSF-DCE", 

659 65: "SESAME", 

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

661 128: "AD-WIN2K-PAC", 

662 129: "AD-ETYPE-NEGOTIATION", 

663 # [MS-KILE] additions 

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

665 142: "KERB-LOCAL", 

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

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

668} 

669 

670 

671class AuthorizationDataItem(ASN1_Packet): 

672 ASN1_codec = ASN1_Codecs.BER 

673 ASN1_root = ASN1F_SEQUENCE( 

674 ASN1F_enum_INTEGER( 

675 "adType", 

676 0, 

677 _AD_TYPES, 

678 explicit_tag=0xA0, 

679 ), 

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

681 ) 

682 

683 

684class AuthorizationData(ASN1_Packet): 

685 ASN1_codec = ASN1_Codecs.BER 

686 ASN1_root = ASN1F_SEQUENCE_OF( 

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

688 ) 

689 

690 def getAuthData(self, adType): 

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

692 

693 

694AD_IF_RELEVANT = AuthorizationData 

695_AUTHORIZATIONDATA_VALUES[1] = AD_IF_RELEVANT 

696 

697 

698class AD_KDCIssued(ASN1_Packet): 

699 ASN1_codec = ASN1_Codecs.BER 

700 ASN1_root = ASN1F_SEQUENCE( 

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

702 ASN1F_optional( 

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

704 ), 

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

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

707 ) 

708 

709 

710_AUTHORIZATIONDATA_VALUES[4] = AD_KDCIssued 

711 

712 

713class AD_AND_OR(ASN1_Packet): 

714 ASN1_codec = ASN1_Codecs.BER 

715 ASN1_root = ASN1F_SEQUENCE( 

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

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

718 ) 

719 

720 

721_AUTHORIZATIONDATA_VALUES[5] = AD_AND_OR 

722 

723ADMANDATORYFORKDC = AuthorizationData 

724_AUTHORIZATIONDATA_VALUES[8] = ADMANDATORYFORKDC 

725 

726 

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

728_PADATA_TYPES = { 

729 1: "PA-TGS-REQ", 

730 2: "PA-ENC-TIMESTAMP", 

731 3: "PA-PW-SALT", 

732 11: "PA-ETYPE-INFO", 

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

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

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

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

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

738 19: "PA-ETYPE-INFO2", 

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

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

741 128: "PA-PAC-REQUEST", 

742 129: "PA-FOR-USER", 

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

744 131: "PA-FOR-CHECK_DUPS", 

745 132: "PA-AS-CHECKSUM", 

746 133: "PA-FX-COOKIE", 

747 134: "PA-AUTHENTICATION-SET", 

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

749 136: "PA-FX-FAST", 

750 137: "PA-FX-ERROR", 

751 138: "PA-ENCRYPTED-CHALLENGE", 

752 141: "PA-OTP-CHALLENGE", 

753 142: "PA-OTP-REQUEST", 

754 143: "PA-OTP-CONFIRM", 

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

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

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

758 147: "PA-PKINIT-KX", 

759 148: "PA-PKU2U-NAME", 

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

761 150: "PA-AS-FRESHNESS", 

762 151: "PA-SPAKE", 

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

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

765 165: "PA-SUPPORTED-ENCTYPES", 

766 166: "PA-EXTENDED-ERROR", 

767 167: "PA-PAC-OPTIONS", 

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

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

770} 

771 

772_PADATA_CLASSES = { 

773 # Filled elsewhere in this file 

774} 

775 

776 

777# RFC4120 

778 

779 

780class _PADATA_value_Field(ASN1F_STRING_PacketField): 

781 """ 

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

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

784 """ 

785 

786 def m2i(self, pkt, s): 

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

788 if pkt.padataType.val in _PADATA_CLASSES: 

789 cls = _PADATA_CLASSES[pkt.padataType.val] 

790 if isinstance(cls, tuple): 

791 parent = pkt.underlayer or pkt.parent 

792 is_reply = False 

793 if parent is not None: 

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

795 is_reply = True 

796 else: 

797 parent = parent.underlayer or parent.parent 

798 is_reply = isinstance(parent, KRB_ERROR) 

799 cls = cls[is_reply] 

800 if not val[0].val: 

801 return val 

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

803 return val 

804 

805 

806class PADATA(ASN1_Packet): 

807 ASN1_codec = ASN1_Codecs.BER 

808 ASN1_root = ASN1F_SEQUENCE( 

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

810 _PADATA_value_Field( 

811 "padataValue", 

812 "", 

813 explicit_tag=0xA2, 

814 ), 

815 ) 

816 

817 

818# RFC 4120 sect 5.2.7.2 

819 

820 

821class PA_ENC_TS_ENC(ASN1_Packet): 

822 ASN1_codec = ASN1_Codecs.BER 

823 ASN1_root = ASN1F_SEQUENCE( 

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

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

826 ) 

827 

828 

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

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

831 

832 

833# RFC 4120 sect 5.2.7.4 

834 

835 

836class ETYPE_INFO_ENTRY(ASN1_Packet): 

837 ASN1_codec = ASN1_Codecs.BER 

838 ASN1_root = ASN1F_SEQUENCE( 

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

840 ASN1F_optional( 

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

842 ), 

843 ) 

844 

845 

846class ETYPE_INFO(ASN1_Packet): 

847 ASN1_codec = ASN1_Codecs.BER 

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

849 

850 

851_PADATA_CLASSES[11] = ETYPE_INFO 

852 

853# RFC 4120 sect 5.2.7.5 

854 

855 

856class ETYPE_INFO_ENTRY2(ASN1_Packet): 

857 ASN1_codec = ASN1_Codecs.BER 

858 ASN1_root = ASN1F_SEQUENCE( 

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

860 ASN1F_optional( 

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

862 ), 

863 ASN1F_optional( 

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

865 ), 

866 ) 

867 

868 

869class ETYPE_INFO2(ASN1_Packet): 

870 ASN1_codec = ASN1_Codecs.BER 

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

872 

873 

874_PADATA_CLASSES[19] = ETYPE_INFO2 

875 

876 

877# RFC8636 - PKINIT Algorithm Agility 

878 

879 

880class TD_CMS_DIGEST_ALGORITHMS(ASN1_Packet): 

881 ASN1_codec = ASN1_Codecs.BER 

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

883 

884 

885_PADATA_CLASSES[111] = TD_CMS_DIGEST_ALGORITHMS 

886 

887 

888# PADATA Extended with RFC6113 

889 

890 

891class PA_AUTHENTICATION_SET_ELEM(ASN1_Packet): 

892 ASN1_codec = ASN1_Codecs.BER 

893 ASN1_root = ASN1F_SEQUENCE( 

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

895 ASN1F_optional( 

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

897 ), 

898 ASN1F_optional( 

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

900 ), 

901 ) 

902 

903 

904class PA_AUTHENTICATION_SET(ASN1_Packet): 

905 ASN1_codec = ASN1_Codecs.BER 

906 ASN1_root = ASN1F_SEQUENCE_OF( 

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

908 ) 

909 

910 

911_PADATA_CLASSES[134] = PA_AUTHENTICATION_SET 

912 

913 

914# [MS-KILE] sect 2.2.3 

915 

916 

917class PA_PAC_REQUEST(ASN1_Packet): 

918 ASN1_codec = ASN1_Codecs.BER 

919 ASN1_root = ASN1F_SEQUENCE( 

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

921 ) 

922 

923 

924_PADATA_CLASSES[128] = PA_PAC_REQUEST 

925 

926 

927# [MS-KILE] sect 2.2.5 

928 

929 

930class LSAP_TOKEN_INFO_INTEGRITY(Packet): 

931 fields_desc = [ 

932 FlagsField( 

933 "Flags", 

934 0, 

935 -32, 

936 { 

937 0x00000001: "UAC-Restricted", 

938 }, 

939 ), 

940 LEIntEnumField( 

941 "TokenIL", 

942 0x00002000, 

943 { 

944 0x00000000: "Untrusted", 

945 0x00001000: "Low", 

946 0x00002000: "Medium", 

947 0x00003000: "High", 

948 0x00004000: "System", 

949 0x00005000: "Protected process", 

950 }, 

951 ), 

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

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

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

955 ] 

956 

957 

958# [MS-KILE] sect 2.2.6 

959 

960 

961class _KerbAdRestrictionEntry_Field(ASN1F_STRING_PacketField): 

962 def m2i(self, pkt, s): 

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

964 if not val[0].val: 

965 return val 

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

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

968 return val 

969 

970 

971class KERB_AD_RESTRICTION_ENTRY(ASN1_Packet): 

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

973 ASN1_codec = ASN1_Codecs.BER 

974 ASN1_root = ASN1F_SEQUENCE( 

975 ASN1F_SEQUENCE( 

976 ASN1F_enum_INTEGER( 

977 "restrictionType", 

978 0, 

979 {0: "LSAP_TOKEN_INFO_INTEGRITY"}, 

980 explicit_tag=0xA0, 

981 ), 

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

983 ) 

984 ) 

985 

986 

987_AUTHORIZATIONDATA_VALUES[141] = KERB_AD_RESTRICTION_ENTRY 

988 

989 

990# [MS-KILE] sect 3.2.5.8 

991 

992 

993class KERB_AUTH_DATA_AP_OPTIONS(Packet): 

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

995 fields_desc = [ 

996 FlagsField( 

997 "apOptions", 

998 0x4000, 

999 -32, 

1000 { 

1001 0x4000: "KERB_AP_OPTIONS_CBT", 

1002 0x8000: "KERB_AP_OPTIONS_UNVERIFIED_TARGET_NAME", 

1003 }, 

1004 ), 

1005 ] 

1006 

1007 

1008_AUTHORIZATIONDATA_VALUES[143] = KERB_AUTH_DATA_AP_OPTIONS 

1009 

1010 

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

1012 

1013 

1014class KERB_AUTH_DATA_CLIENT_TARGET(Packet): 

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

1016 fields_desc = [ 

1017 StrFieldUtf16("spn", ""), 

1018 ] 

1019 

1020 

1021_AUTHORIZATIONDATA_VALUES[144] = KERB_AUTH_DATA_CLIENT_TARGET 

1022 

1023 

1024# RFC6806 sect 6 

1025 

1026 

1027class KERB_AD_LOGIN_ALIAS(ASN1_Packet): 

1028 ASN1_codec = ASN1_Codecs.BER 

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

1030 

1031 

1032_AUTHORIZATIONDATA_VALUES[80] = KERB_AD_LOGIN_ALIAS 

1033 

1034 

1035# [MS-KILE] sect 2.2.8 

1036 

1037 

1038class PA_SUPPORTED_ENCTYPES(Packet): 

1039 fields_desc = [ 

1040 FlagsField( 

1041 "flags", 

1042 0, 

1043 -32, 

1044 [ 

1045 "DES-CBC-CRC", 

1046 "DES-CBC-MD5", 

1047 "RC4-HMAC", 

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

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

1050 ] 

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

1052 + [ 

1053 "FAST-supported", 

1054 "Compount-identity-supported", 

1055 "Claims-supported", 

1056 "Resource-SID-compression-disabled", 

1057 ], 

1058 ) 

1059 ] 

1060 

1061 

1062_PADATA_CLASSES[165] = PA_SUPPORTED_ENCTYPES 

1063 

1064# [MS-KILE] sect 2.2.10 

1065 

1066 

1067class PA_PAC_OPTIONS(ASN1_Packet): 

1068 ASN1_codec = ASN1_Codecs.BER 

1069 ASN1_root = ASN1F_SEQUENCE( 

1070 KerberosFlags( 

1071 "options", 

1072 "", 

1073 [ 

1074 "Claims", 

1075 "Branch-Aware", 

1076 "Forward-to-Full-DC", 

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

1078 ], 

1079 explicit_tag=0xA0, 

1080 ) 

1081 ) 

1082 

1083 

1084_PADATA_CLASSES[167] = PA_PAC_OPTIONS 

1085 

1086# [MS-KILE] sect 2.2.11 

1087 

1088 

1089class KERB_KEY_LIST_REQ(ASN1_Packet): 

1090 ASN1_codec = ASN1_Codecs.BER 

1091 ASN1_root = ASN1F_SEQUENCE_OF( 

1092 "keytypes", 

1093 [], 

1094 ASN1F_enum_INTEGER("", 0, _KRB_E_TYPES), 

1095 ) 

1096 

1097 

1098_PADATA_CLASSES[161] = KERB_KEY_LIST_REQ 

1099 

1100# [MS-KILE] sect 2.2.12 

1101 

1102 

1103class KERB_KEY_LIST_REP(ASN1_Packet): 

1104 ASN1_codec = ASN1_Codecs.BER 

1105 ASN1_root = ASN1F_SEQUENCE_OF( 

1106 "keys", 

1107 [], 

1108 ASN1F_PACKET("", None, EncryptionKey), 

1109 ) 

1110 

1111 

1112_PADATA_CLASSES[162] = KERB_KEY_LIST_REP 

1113 

1114# [MS-KILE] sect 2.2.13 

1115 

1116 

1117class KERB_SUPERSEDED_BY_USER(ASN1_Packet): 

1118 ASN1_codec = ASN1_Codecs.BER 

1119 ASN1_root = ASN1F_SEQUENCE( 

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

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

1122 ) 

1123 

1124 

1125_PADATA_CLASSES[170] = KERB_SUPERSEDED_BY_USER 

1126 

1127 

1128# [MS-KILE] sect 2.2.14 

1129 

1130 

1131class KERB_DMSA_KEY_PACKAGE(ASN1_Packet): 

1132 ASN1_codec = ASN1_Codecs.BER 

1133 ASN1_root = ASN1F_SEQUENCE( 

1134 ASN1F_SEQUENCE_OF( 

1135 "currentKeys", 

1136 [], 

1137 ASN1F_PACKET("", None, EncryptionKey), 

1138 explicit_tag=0xA0, 

1139 ), 

1140 ASN1F_optional( 

1141 ASN1F_SEQUENCE_OF( 

1142 "previousKeys", 

1143 [], 

1144 ASN1F_PACKET("", None, EncryptionKey), 

1145 explicit_tag=0xA1, 

1146 ), 

1147 ), 

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

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

1150 ) 

1151 

1152 

1153_PADATA_CLASSES[171] = KERB_DMSA_KEY_PACKAGE 

1154 

1155 

1156# RFC6113 sect 5.4.1 

1157 

1158 

1159class _KrbFastArmor_value_Field(ASN1F_STRING_PacketField): 

1160 def m2i(self, pkt, s): 

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

1162 if not val[0].val: 

1163 return val 

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

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

1166 return val 

1167 

1168 

1169class KrbFastArmor(ASN1_Packet): 

1170 ASN1_codec = ASN1_Codecs.BER 

1171 ASN1_root = ASN1F_SEQUENCE( 

1172 ASN1F_enum_INTEGER( 

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

1174 ), 

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

1176 ) 

1177 

1178 

1179# RFC6113 sect 5.4.2 

1180 

1181 

1182class KrbFastArmoredReq(ASN1_Packet): 

1183 ASN1_codec = ASN1_Codecs.BER 

1184 ASN1_root = ASN1F_SEQUENCE( 

1185 ASN1F_SEQUENCE( 

1186 ASN1F_optional( 

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

1188 ), 

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

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

1191 ) 

1192 ) 

1193 

1194 

1195class PA_FX_FAST_REQUEST(ASN1_Packet): 

1196 ASN1_codec = ASN1_Codecs.BER 

1197 ASN1_root = ASN1F_CHOICE( 

1198 "armoredData", 

1199 ASN1_STRING(""), 

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

1201 ) 

1202 

1203 

1204# RFC6113 sect 5.4.3 

1205 

1206 

1207class KrbFastArmoredRep(ASN1_Packet): 

1208 ASN1_codec = ASN1_Codecs.BER 

1209 ASN1_root = ASN1F_SEQUENCE( 

1210 ASN1F_SEQUENCE( 

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

1212 ) 

1213 ) 

1214 

1215 

1216class PA_FX_FAST_REPLY(ASN1_Packet): 

1217 ASN1_codec = ASN1_Codecs.BER 

1218 ASN1_root = ASN1F_CHOICE( 

1219 "armoredData", 

1220 ASN1_STRING(""), 

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

1222 ) 

1223 

1224 

1225class KrbFastFinished(ASN1_Packet): 

1226 ASN1_codec = ASN1_Codecs.BER 

1227 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

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

1233 ) 

1234 

1235 

1236class KrbFastResponse(ASN1_Packet): 

1237 ASN1_codec = ASN1_Codecs.BER 

1238 ASN1_root = ASN1F_SEQUENCE( 

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

1240 ASN1F_optional( 

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

1242 ), 

1243 ASN1F_optional( 

1244 ASN1F_PACKET( 

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

1246 ) 

1247 ), 

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

1249 ) 

1250 

1251 

1252_PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY) 

1253 

1254 

1255# RFC 4556 - PKINIT 

1256 

1257 

1258# sect 3.2.1 

1259 

1260 

1261class ExternalPrincipalIdentifier(ASN1_Packet): 

1262 ASN1_codec = ASN1_Codecs.BER 

1263 ASN1_root = ASN1F_SEQUENCE( 

1264 ASN1F_optional( 

1265 ASN1F_STRING_ENCAPS( 

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

1267 ), 

1268 ), 

1269 ASN1F_optional( 

1270 ASN1F_STRING_ENCAPS( 

1271 "issuerAndSerialNumber", 

1272 None, 

1273 CMS_IssuerAndSerialNumber, 

1274 implicit_tag=0x81, 

1275 ), 

1276 ), 

1277 ASN1F_optional( 

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

1279 ), 

1280 ) 

1281 

1282 

1283class PA_PK_AS_REQ(ASN1_Packet): 

1284 ASN1_codec = ASN1_Codecs.BER 

1285 ASN1_root = ASN1F_SEQUENCE( 

1286 ASN1F_STRING_ENCAPS( 

1287 "signedAuthpack", 

1288 CMS_ContentInfo(), 

1289 CMS_ContentInfo, 

1290 implicit_tag=0x80, 

1291 ), 

1292 ASN1F_optional( 

1293 ASN1F_SEQUENCE_OF( 

1294 "trustedCertifiers", 

1295 None, 

1296 ExternalPrincipalIdentifier, 

1297 explicit_tag=0xA1, 

1298 ), 

1299 ), 

1300 ASN1F_optional( 

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

1302 ), 

1303 ) 

1304 

1305 

1306_PADATA_CLASSES[16] = PA_PK_AS_REQ 

1307 

1308 

1309# [MS-PKCA] sect 2.2.3 

1310 

1311 

1312class PAChecksum2(ASN1_Packet): 

1313 ASN1_codec = ASN1_Codecs.BER 

1314 ASN1_root = ASN1F_SEQUENCE( 

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

1316 ASN1F_PACKET( 

1317 "algorithmIdentifier", 

1318 X509_AlgorithmIdentifier(), 

1319 X509_AlgorithmIdentifier, 

1320 explicit_tag=0xA1, 

1321 ), 

1322 ) 

1323 

1324 def verify(self, text): 

1325 """ 

1326 Verify a checksum of text. 

1327 

1328 :param text: the bytes to verify 

1329 """ 

1330 # [MS-PKCA] 2.2.3 - PAChecksum2 

1331 

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

1333 oid = self.algorithmIdentifier.algorithm.val 

1334 if oid == "1.3.14.3.2.26": 

1335 hashcls = Hash_SHA 

1336 elif oid == "2.16.840.1.101.3.4.2.1": 

1337 hashcls = Hash_SHA256 

1338 elif oid == "2.16.840.1.101.3.4.2.2": 

1339 hashcls = Hash_SHA384 

1340 elif oid == "2.16.840.1.101.3.4.2.3": 

1341 hashcls = Hash_SHA512 

1342 else: 

1343 raise ValueError("Bad PAChecksum2 checksum !") 

1344 

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

1346 raise ValueError("Bad PAChecksum2 checksum !") 

1347 

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

1349 """ 

1350 Make a checksum. 

1351 

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

1353 """ 

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

1355 if h == "sha1": 

1356 hashcls = Hash_SHA 

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

1358 elif h == "sha256": 

1359 hashcls = Hash_SHA256 

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

1361 elif h == "sha384": 

1362 hashcls = Hash_SHA384 

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

1364 elif h == "sha512": 

1365 hashcls = Hash_SHA512 

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

1367 else: 

1368 raise ValueError("Bad PAChecksum2 checksum !") 

1369 

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

1371 

1372 

1373# still RFC 4556 sect 3.2.1 

1374 

1375 

1376class KRB_PKAuthenticator(ASN1_Packet): 

1377 ASN1_codec = ASN1_Codecs.BER 

1378 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

1382 ASN1F_optional( 

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

1384 ), 

1385 # RFC8070 extension 

1386 ASN1F_optional( 

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

1388 ), 

1389 # [MS-PKCA] sect 2.2.3 

1390 ASN1F_optional( 

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

1392 ), 

1393 ) 

1394 

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

1396 """ 

1397 Populate paChecksum 

1398 """ 

1399 # paChecksum (always sha-1) 

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

1401 

1402 # paChecksum2 

1403 if h != "sha1": 

1404 self.paChecksum2 = PAChecksum2() 

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

1406 

1407 def verify_checksum(self, text): 

1408 """ 

1409 Verify paChecksum and paChecksum2 

1410 """ 

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

1412 raise ValueError("Bad paChecksum checksum !") 

1413 

1414 if self.paChecksum2 is not None: 

1415 self.paChecksum2.verify(text) 

1416 

1417 

1418# RFC8636 sect 6 

1419 

1420 

1421class KDFAlgorithmId(ASN1_Packet): 

1422 ASN1_codec = ASN1_Codecs.BER 

1423 ASN1_root = ASN1F_SEQUENCE( 

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

1425 ) 

1426 

1427 

1428# still RFC 4556 sect 3.2.1 

1429 

1430 

1431class KRB_AuthPack(ASN1_Packet): 

1432 ASN1_codec = ASN1_Codecs.BER 

1433 ASN1_root = ASN1F_SEQUENCE( 

1434 ASN1F_PACKET( 

1435 "pkAuthenticator", 

1436 KRB_PKAuthenticator(), 

1437 KRB_PKAuthenticator, 

1438 explicit_tag=0xA0, 

1439 ), 

1440 ASN1F_optional( 

1441 ASN1F_PACKET( 

1442 "clientPublicValue", 

1443 X509_SubjectPublicKeyInfo(), 

1444 X509_SubjectPublicKeyInfo, 

1445 explicit_tag=0xA1, 

1446 ), 

1447 ), 

1448 ASN1F_optional( 

1449 ASN1F_SEQUENCE_OF( 

1450 "supportedCMSTypes", 

1451 None, 

1452 X509_AlgorithmIdentifier, 

1453 explicit_tag=0xA2, 

1454 ), 

1455 ), 

1456 ASN1F_optional( 

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

1458 ), 

1459 # RFC8636 extension 

1460 ASN1F_optional( 

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

1462 ), 

1463 ) 

1464 

1465 

1466_CMS_ENCAPSULATED["1.3.6.1.5.2.3.1"] = KRB_AuthPack 

1467 

1468# sect 3.2.3 

1469 

1470 

1471class DHRepInfo(ASN1_Packet): 

1472 ASN1_codec = ASN1_Codecs.BER 

1473 ASN1_root = ASN1F_SEQUENCE( 

1474 ASN1F_STRING_ENCAPS( 

1475 "dhSignedData", 

1476 CMS_ContentInfo(), 

1477 CMS_ContentInfo, 

1478 implicit_tag=0x80, 

1479 ), 

1480 ASN1F_optional( 

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

1482 ), 

1483 # RFC8636 extension 

1484 ASN1F_optional( 

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

1486 ), 

1487 ) 

1488 

1489 

1490class EncKeyPack(ASN1_Packet): 

1491 ASN1_codec = ASN1_Codecs.BER 

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

1493 

1494 

1495class PA_PK_AS_REP(ASN1_Packet): 

1496 ASN1_codec = ASN1_Codecs.BER 

1497 ASN1_root = ASN1F_CHOICE( 

1498 "rep", 

1499 ASN1_STRING(""), 

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

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

1502 ) 

1503 

1504 

1505_PADATA_CLASSES[17] = PA_PK_AS_REP 

1506 

1507 

1508class KDCDHKeyInfo(ASN1_Packet): 

1509 ASN1_codec = ASN1_Codecs.BER 

1510 ASN1_root = ASN1F_SEQUENCE( 

1511 ASN1F_BIT_STRING_ENCAPS( 

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

1513 ), 

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

1515 ASN1F_optional( 

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

1517 ), 

1518 ) 

1519 

1520 

1521_CMS_ENCAPSULATED["1.3.6.1.5.2.3.2"] = KDCDHKeyInfo 

1522 

1523# [MS-SFU] 

1524 

1525 

1526# sect 2.2.1 

1527class PA_FOR_USER(ASN1_Packet): 

1528 ASN1_codec = ASN1_Codecs.BER 

1529 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

1534 ) 

1535 

1536 

1537_PADATA_CLASSES[129] = PA_FOR_USER 

1538 

1539 

1540# sect 2.2.2 

1541 

1542 

1543class S4UUserID(ASN1_Packet): 

1544 ASN1_codec = ASN1_Codecs.BER 

1545 ASN1_root = ASN1F_SEQUENCE( 

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

1547 ASN1F_optional( 

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

1549 ), 

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

1551 ASN1F_optional( 

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

1553 ), 

1554 ASN1F_optional( 

1555 ASN1F_FLAGS( 

1556 "options", 

1557 "", 

1558 [ 

1559 "reserved", 

1560 "KDC_CHECK_LOGON_HOUR_RESTRICTIONS", 

1561 "USE_REPLY_KEY_USAGE", 

1562 "NT_AUTH_POLICY_NOT_REQUIRED", 

1563 "UNCONDITIONAL_DELEGATION", 

1564 ], 

1565 explicit_tag=0xA4, 

1566 ) 

1567 ), 

1568 ) 

1569 

1570 

1571class PA_S4U_X509_USER(ASN1_Packet): 

1572 ASN1_codec = ASN1_Codecs.BER 

1573 ASN1_root = ASN1F_SEQUENCE( 

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

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

1576 ) 

1577 

1578 

1579_PADATA_CLASSES[130] = PA_S4U_X509_USER 

1580 

1581 

1582# Back to RFC4120 

1583 

1584# sect 5.10 

1585KRB_MSG_TYPES = { 

1586 1: "Ticket", 

1587 2: "Authenticator", 

1588 3: "EncTicketPart", 

1589 10: "AS-REQ", 

1590 11: "AS-REP", 

1591 12: "TGS-REQ", 

1592 13: "TGS-REP", 

1593 14: "AP-REQ", 

1594 15: "AP-REP", 

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

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

1597 20: "KRB-SAFE", 

1598 21: "KRB-PRIV", 

1599 22: "KRB-CRED", 

1600 25: "EncASRepPart", 

1601 26: "EncTGSRepPart", 

1602 27: "EncAPRepPart", 

1603 28: "EncKrbPrivPart", 

1604 29: "EnvKrbCredPart", 

1605 30: "KRB-ERROR", 

1606} 

1607 

1608# sect 5.3 

1609 

1610 

1611class KRB_Ticket(ASN1_Packet): 

1612 ASN1_codec = ASN1_Codecs.BER 

1613 ASN1_root = ASN1F_SEQUENCE( 

1614 ASN1F_SEQUENCE( 

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

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

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

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

1619 ), 

1620 implicit_tag=ASN1_Class_KRB.Ticket, 

1621 ) 

1622 

1623 def getSPN(self): 

1624 return "%s@%s" % ( 

1625 self.sname.toString(), 

1626 self.realm.val.decode(), 

1627 ) 

1628 

1629 

1630class TransitedEncoding(ASN1_Packet): 

1631 ASN1_codec = ASN1_Codecs.BER 

1632 ASN1_root = ASN1F_SEQUENCE( 

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

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

1635 ) 

1636 

1637 

1638_TICKET_FLAGS = [ 

1639 "reserved", 

1640 "forwardable", 

1641 "forwarded", 

1642 "proxiable", 

1643 "proxy", 

1644 "may-postdate", 

1645 "postdated", 

1646 "invalid", 

1647 "renewable", 

1648 "initial", 

1649 "pre-authent", 

1650 "hw-authent", 

1651 "transited-since-policy-checked", 

1652 "ok-as-delegate", 

1653 "unused", 

1654 "canonicalize", # RFC6806 

1655 "anonymous", # RFC6112 + RFC8129 

1656] 

1657 

1658 

1659class EncTicketPart(ASN1_Packet): 

1660 ASN1_codec = ASN1_Codecs.BER 

1661 ASN1_root = ASN1F_SEQUENCE( 

1662 ASN1F_SEQUENCE( 

1663 KerberosFlags( 

1664 "flags", 

1665 "", 

1666 _TICKET_FLAGS, 

1667 explicit_tag=0xA0, 

1668 ), 

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

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

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

1672 ASN1F_PACKET( 

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

1674 ), 

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

1676 ASN1F_optional( 

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

1678 ), 

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

1680 ASN1F_optional( 

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

1682 ), 

1683 ASN1F_optional( 

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

1685 ), 

1686 ASN1F_optional( 

1687 ASN1F_PACKET( 

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

1689 ), 

1690 ), 

1691 ), 

1692 implicit_tag=ASN1_Class_KRB.EncTicketPart, 

1693 ) 

1694 

1695 

1696# sect 5.4.1 

1697 

1698 

1699class KRB_KDC_REQ_BODY(ASN1_Packet): 

1700 ASN1_codec = ASN1_Codecs.BER 

1701 ASN1_root = ASN1F_SEQUENCE( 

1702 KerberosFlags( 

1703 "kdcOptions", 

1704 "", 

1705 [ 

1706 "reserved", 

1707 "forwardable", 

1708 "forwarded", 

1709 "proxiable", 

1710 "proxy", 

1711 "allow-postdate", 

1712 "postdated", 

1713 "unused7", 

1714 "renewable", 

1715 "unused9", 

1716 "unused10", 

1717 "opt-hardware-auth", 

1718 "unused12", 

1719 "unused13", 

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

1721 "canonicalize", # RFC6806 

1722 "request-anonymous", # RFC6112 + RFC8129 

1723 ] 

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

1725 + [ 

1726 "disable-transited-check", 

1727 "renewable-ok", 

1728 "enc-tkt-in-skey", 

1729 "unused29", 

1730 "renew", 

1731 "validate", 

1732 ], 

1733 explicit_tag=0xA0, 

1734 ), 

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

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

1737 ASN1F_optional( 

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

1739 ), 

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

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

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

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

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

1745 ASN1F_optional( 

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

1747 ), 

1748 ASN1F_optional( 

1749 ASN1F_PACKET( 

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

1751 ), 

1752 ), 

1753 ASN1F_optional( 

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

1755 ), 

1756 ) 

1757 

1758 

1759KRB_KDC_REQ = ASN1F_SEQUENCE( 

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

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

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

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

1764) 

1765 

1766 

1767class KrbFastReq(ASN1_Packet): 

1768 # RFC6113 sect 5.4.2 

1769 ASN1_codec = ASN1_Codecs.BER 

1770 ASN1_root = ASN1F_SEQUENCE( 

1771 KerberosFlags( 

1772 "fastOptions", 

1773 "", 

1774 [ 

1775 "RESERVED", 

1776 "hide-client-names", 

1777 ] 

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

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

1780 explicit_tag=0xA0, 

1781 ), 

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

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

1784 ) 

1785 

1786 

1787class KRB_AS_REQ(ASN1_Packet): 

1788 ASN1_codec = ASN1_Codecs.BER 

1789 ASN1_root = ASN1F_SEQUENCE( 

1790 KRB_KDC_REQ, 

1791 implicit_tag=ASN1_Class_KRB.AS_REQ, 

1792 ) 

1793 

1794 

1795class KRB_TGS_REQ(ASN1_Packet): 

1796 ASN1_codec = ASN1_Codecs.BER 

1797 ASN1_root = ASN1F_SEQUENCE( 

1798 KRB_KDC_REQ, 

1799 implicit_tag=ASN1_Class_KRB.TGS_REQ, 

1800 ) 

1801 msgType = ASN1_INTEGER(12) 

1802 

1803 

1804# sect 5.4.2 

1805 

1806KRB_KDC_REP = ASN1F_SEQUENCE( 

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

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

1809 ASN1F_optional( 

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

1811 ), 

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

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

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

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

1816) 

1817 

1818 

1819class KRB_AS_REP(ASN1_Packet): 

1820 ASN1_codec = ASN1_Codecs.BER 

1821 ASN1_root = ASN1F_SEQUENCE( 

1822 KRB_KDC_REP, 

1823 implicit_tag=ASN1_Class_KRB.AS_REP, 

1824 ) 

1825 

1826 def getUPN(self): 

1827 return "%s@%s" % ( 

1828 self.cname.toString(), 

1829 self.crealm.val.decode(), 

1830 ) 

1831 

1832 

1833class KRB_TGS_REP(ASN1_Packet): 

1834 ASN1_codec = ASN1_Codecs.BER 

1835 ASN1_root = ASN1F_SEQUENCE( 

1836 KRB_KDC_REP, 

1837 implicit_tag=ASN1_Class_KRB.TGS_REP, 

1838 ) 

1839 

1840 def getUPN(self): 

1841 return "%s@%s" % ( 

1842 self.cname.toString(), 

1843 self.crealm.val.decode(), 

1844 ) 

1845 

1846 

1847class LastReqItem(ASN1_Packet): 

1848 ASN1_codec = ASN1_Codecs.BER 

1849 ASN1_root = ASN1F_SEQUENCE( 

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

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

1852 ) 

1853 

1854 

1855EncKDCRepPart = ASN1F_SEQUENCE( 

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

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

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

1859 ASN1F_optional( 

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

1861 ), 

1862 KerberosFlags( 

1863 "flags", 

1864 "", 

1865 _TICKET_FLAGS, 

1866 explicit_tag=0xA4, 

1867 ), 

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

1869 ASN1F_optional( 

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

1871 ), 

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

1873 ASN1F_optional( 

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

1875 ), 

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

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

1878 ASN1F_optional( 

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

1880 ), 

1881 # RFC6806 sect 11 

1882 ASN1F_optional( 

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

1884 ), 

1885) 

1886 

1887 

1888class EncASRepPart(ASN1_Packet): 

1889 ASN1_codec = ASN1_Codecs.BER 

1890 ASN1_root = ASN1F_SEQUENCE( 

1891 EncKDCRepPart, 

1892 implicit_tag=ASN1_Class_KRB.EncASRepPart, 

1893 ) 

1894 

1895 

1896class EncTGSRepPart(ASN1_Packet): 

1897 ASN1_codec = ASN1_Codecs.BER 

1898 ASN1_root = ASN1F_SEQUENCE( 

1899 EncKDCRepPart, 

1900 implicit_tag=ASN1_Class_KRB.EncTGSRepPart, 

1901 ) 

1902 

1903 

1904# sect 5.5.1 

1905 

1906 

1907class KRB_AP_REQ(ASN1_Packet): 

1908 ASN1_codec = ASN1_Codecs.BER 

1909 ASN1_root = ASN1F_SEQUENCE( 

1910 ASN1F_SEQUENCE( 

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

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

1913 KerberosFlags( 

1914 "apOptions", 

1915 "", 

1916 [ 

1917 "reserved", 

1918 "use-session-key", 

1919 "mutual-required", 

1920 ], 

1921 explicit_tag=0xA2, 

1922 ), 

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

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

1925 ), 

1926 implicit_tag=ASN1_Class_KRB.AP_REQ, 

1927 ) 

1928 

1929 

1930_PADATA_CLASSES[1] = KRB_AP_REQ 

1931 

1932 

1933class KRB_Authenticator(ASN1_Packet): 

1934 ASN1_codec = ASN1_Codecs.BER 

1935 ASN1_root = ASN1F_SEQUENCE( 

1936 ASN1F_SEQUENCE( 

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

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

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

1940 ASN1F_optional( 

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

1942 ), 

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

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

1945 ASN1F_optional( 

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

1947 ), 

1948 ASN1F_optional( 

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

1950 ), 

1951 ASN1F_optional( 

1952 ASN1F_PACKET( 

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

1954 ), 

1955 ), 

1956 ), 

1957 implicit_tag=ASN1_Class_KRB.Authenticator, 

1958 ) 

1959 

1960 

1961# sect 5.5.2 

1962 

1963 

1964class KRB_AP_REP(ASN1_Packet): 

1965 ASN1_codec = ASN1_Codecs.BER 

1966 ASN1_root = ASN1F_SEQUENCE( 

1967 ASN1F_SEQUENCE( 

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

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

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

1971 ), 

1972 implicit_tag=ASN1_Class_KRB.AP_REP, 

1973 ) 

1974 

1975 

1976class EncAPRepPart(ASN1_Packet): 

1977 ASN1_codec = ASN1_Codecs.BER 

1978 ASN1_root = ASN1F_SEQUENCE( 

1979 ASN1F_SEQUENCE( 

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

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

1982 ASN1F_optional( 

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

1984 ), 

1985 ASN1F_optional( 

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

1987 ), 

1988 ), 

1989 implicit_tag=ASN1_Class_KRB.EncAPRepPart, 

1990 ) 

1991 

1992 

1993# sect 5.7 

1994 

1995 

1996class KRB_PRIV(ASN1_Packet): 

1997 ASN1_codec = ASN1_Codecs.BER 

1998 ASN1_root = ASN1F_SEQUENCE( 

1999 ASN1F_SEQUENCE( 

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

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

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

2003 ), 

2004 implicit_tag=ASN1_Class_KRB.PRIV, 

2005 ) 

2006 

2007 

2008class EncKrbPrivPart(ASN1_Packet): 

2009 ASN1_codec = ASN1_Codecs.BER 

2010 ASN1_root = ASN1F_SEQUENCE( 

2011 ASN1F_SEQUENCE( 

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

2013 ASN1F_optional( 

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

2015 ), 

2016 ASN1F_optional( 

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

2018 ), 

2019 ASN1F_optional( 

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

2021 ), 

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

2023 ASN1F_optional( 

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

2025 ), 

2026 ), 

2027 implicit_tag=ASN1_Class_KRB.EncKrbPrivPart, 

2028 ) 

2029 

2030 

2031# sect 5.8 

2032 

2033 

2034class KRB_CRED(ASN1_Packet): 

2035 ASN1_codec = ASN1_Codecs.BER 

2036 ASN1_root = ASN1F_SEQUENCE( 

2037 ASN1F_SEQUENCE( 

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

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

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

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

2042 ), 

2043 implicit_tag=ASN1_Class_KRB.CRED, 

2044 ) 

2045 

2046 

2047class KrbCredInfo(ASN1_Packet): 

2048 ASN1_codec = ASN1_Codecs.BER 

2049 ASN1_root = ASN1F_SEQUENCE( 

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

2051 ASN1F_optional( 

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

2053 ), 

2054 ASN1F_optional( 

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

2056 ), 

2057 ASN1F_optional( 

2058 KerberosFlags( 

2059 "flags", 

2060 None, 

2061 _TICKET_FLAGS, 

2062 explicit_tag=0xA3, 

2063 ), 

2064 ), 

2065 ASN1F_optional( 

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

2067 ), 

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

2069 ASN1F_optional( 

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

2071 ), 

2072 ASN1F_optional( 

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

2074 ), 

2075 ASN1F_optional( 

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

2077 ), 

2078 ASN1F_optional( 

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

2080 ), 

2081 ASN1F_optional( 

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

2083 ), 

2084 ) 

2085 

2086 

2087class EncKrbCredPart(ASN1_Packet): 

2088 ASN1_codec = ASN1_Codecs.BER 

2089 ASN1_root = ASN1F_SEQUENCE( 

2090 ASN1F_SEQUENCE( 

2091 ASN1F_SEQUENCE_OF( 

2092 "ticketInfo", 

2093 [KrbCredInfo()], 

2094 KrbCredInfo, 

2095 explicit_tag=0xA0, 

2096 ), 

2097 ASN1F_optional( 

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

2099 ), 

2100 ASN1F_optional( 

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

2102 ), 

2103 ASN1F_optional( 

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

2105 ), 

2106 ASN1F_optional( 

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

2108 ), 

2109 ASN1F_optional( 

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

2111 ), 

2112 ), 

2113 implicit_tag=ASN1_Class_KRB.EncKrbCredPart, 

2114 ) 

2115 

2116 

2117# sect 5.9.1 

2118 

2119 

2120class MethodData(ASN1_Packet): 

2121 ASN1_codec = ASN1_Codecs.BER 

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

2123 

2124 

2125class _KRBERROR_data_Field(ASN1F_STRING_PacketField): 

2126 def m2i(self, pkt, s): 

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

2128 if not val[0].val: 

2129 return val 

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

2131 # 14: KDC_ERR_ETYPE_NOSUPP 

2132 # 24: KDC_ERR_PREAUTH_FAILED 

2133 # 25: KDC_ERR_PREAUTH_REQUIRED 

2134 # 36: KRB_AP_ERR_BADMATCH 

2135 # 80: KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED 

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

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

2138 # 6: KDC_ERR_C_PRINCIPAL_UNKNOWN 

2139 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

2140 # 12: KDC_ERR_POLICY 

2141 # 13: KDC_ERR_BADOPTION 

2142 # 18: KDC_ERR_CLIENT_REVOKED 

2143 # 29: KDC_ERR_SVC_UNAVAILABLE 

2144 # 32: KRB_AP_ERR_TKT_EXPIRED 

2145 # 41: KRB_AP_ERR_MODIFIED 

2146 # 60: KRB_ERR_GENERIC 

2147 # 62: KERB_ERR_TYPE_EXTENDED 

2148 try: 

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

2150 except BER_Decoding_Error: 

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

2152 # Some types can also happen in FAST sessions 

2153 # 18: KDC_ERR_CLIENT_REVOKED 

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

2155 elif pkt.errorCode.val == 7: 

2156 # This looks like an undocumented structure. 

2157 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

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

2159 raise 

2160 elif pkt.errorCode.val == 69: 

2161 # KRB_AP_ERR_USER_TO_USER_REQUIRED 

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

2163 return val 

2164 

2165 

2166class KRB_ERROR(ASN1_Packet): 

2167 ASN1_codec = ASN1_Codecs.BER 

2168 ASN1_root = ASN1F_SEQUENCE( 

2169 ASN1F_SEQUENCE( 

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

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

2172 ASN1F_optional( 

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

2174 ), 

2175 ASN1F_optional( 

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

2177 ), 

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

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

2180 ASN1F_enum_INTEGER( 

2181 "errorCode", 

2182 0, 

2183 { 

2184 # RFC4120 sect 7.5.9 

2185 0: "KDC_ERR_NONE", 

2186 1: "KDC_ERR_NAME_EXP", 

2187 2: "KDC_ERR_SERVICE_EXP", 

2188 3: "KDC_ERR_BAD_PVNO", 

2189 4: "KDC_ERR_C_OLD_MAST_KVNO", 

2190 5: "KDC_ERR_S_OLD_MAST_KVNO", 

2191 6: "KDC_ERR_C_PRINCIPAL_UNKNOWN", 

2192 7: "KDC_ERR_S_PRINCIPAL_UNKNOWN", 

2193 8: "KDC_ERR_PRINCIPAL_NOT_UNIQUE", 

2194 9: "KDC_ERR_NULL_KEY", 

2195 10: "KDC_ERR_CANNOT_POSTDATE", 

2196 11: "KDC_ERR_NEVER_VALID", 

2197 12: "KDC_ERR_POLICY", 

2198 13: "KDC_ERR_BADOPTION", 

2199 14: "KDC_ERR_ETYPE_NOSUPP", 

2200 15: "KDC_ERR_SUMTYPE_NOSUPP", 

2201 16: "KDC_ERR_PADATA_TYPE_NOSUPP", 

2202 17: "KDC_ERR_TRTYPE_NOSUPP", 

2203 18: "KDC_ERR_CLIENT_REVOKED", 

2204 19: "KDC_ERR_SERVICE_REVOKED", 

2205 20: "KDC_ERR_TGT_REVOKED", 

2206 21: "KDC_ERR_CLIENT_NOTYET", 

2207 22: "KDC_ERR_SERVICE_NOTYET", 

2208 23: "KDC_ERR_KEY_EXPIRED", 

2209 24: "KDC_ERR_PREAUTH_FAILED", 

2210 25: "KDC_ERR_PREAUTH_REQUIRED", 

2211 26: "KDC_ERR_SERVER_NOMATCH", 

2212 27: "KDC_ERR_MUST_USE_USER2USER", 

2213 28: "KDC_ERR_PATH_NOT_ACCEPTED", 

2214 29: "KDC_ERR_SVC_UNAVAILABLE", 

2215 31: "KRB_AP_ERR_BAD_INTEGRITY", 

2216 32: "KRB_AP_ERR_TKT_EXPIRED", 

2217 33: "KRB_AP_ERR_TKT_NYV", 

2218 34: "KRB_AP_ERR_REPEAT", 

2219 35: "KRB_AP_ERR_NOT_US", 

2220 36: "KRB_AP_ERR_BADMATCH", 

2221 37: "KRB_AP_ERR_SKEW", 

2222 38: "KRB_AP_ERR_BADADDR", 

2223 39: "KRB_AP_ERR_BADVERSION", 

2224 40: "KRB_AP_ERR_MSG_TYPE", 

2225 41: "KRB_AP_ERR_MODIFIED", 

2226 42: "KRB_AP_ERR_BADORDER", 

2227 44: "KRB_AP_ERR_BADKEYVER", 

2228 45: "KRB_AP_ERR_NOKEY", 

2229 46: "KRB_AP_ERR_MUT_FAIL", 

2230 47: "KRB_AP_ERR_BADDIRECTION", 

2231 48: "KRB_AP_ERR_METHOD", 

2232 49: "KRB_AP_ERR_BADSEQ", 

2233 50: "KRB_AP_ERR_INAPP_CKSUM", 

2234 51: "KRB_AP_PATH_NOT_ACCEPTED", 

2235 52: "KRB_ERR_RESPONSE_TOO_BIG", 

2236 60: "KRB_ERR_GENERIC", 

2237 61: "KRB_ERR_FIELD_TOOLONG", 

2238 # RFC4556 

2239 62: "KDC_ERR_CLIENT_NOT_TRUSTED", 

2240 63: "KDC_ERR_KDC_NOT_TRUSTED", 

2241 64: "KDC_ERR_INVALID_SIG", 

2242 65: "KDC_ERR_KEY_TOO_WEAK", 

2243 66: "KDC_ERR_CERTIFICATE_MISMATCH", 

2244 67: "KRB_AP_ERR_NO_TGT", 

2245 68: "KDC_ERR_WRONG_REALM", 

2246 69: "KRB_AP_ERR_USER_TO_USER_REQUIRED", 

2247 70: "KDC_ERR_CANT_VERIFY_CERTIFICATE", 

2248 71: "KDC_ERR_INVALID_CERTIFICATE", 

2249 72: "KDC_ERR_REVOKED_CERTIFICATE", 

2250 73: "KDC_ERR_REVOCATION_STATUS_UNKNOWN", 

2251 74: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE", 

2252 75: "KDC_ERR_CLIENT_NAME_MISMATCH", 

2253 76: "KDC_ERR_KDC_NAME_MISMATCH", 

2254 77: "KDC_ERR_INCONSISTENT_KEY_PURPOSE", 

2255 78: "KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED", 

2256 79: "KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED", 

2257 80: "KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED", 

2258 81: "KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED", 

2259 # draft-ietf-kitten-iakerb 

2260 85: "KRB_AP_ERR_IAKERB_KDC_NOT_FOUND", 

2261 86: "KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE", 

2262 # RFC6113 

2263 90: "KDC_ERR_PREAUTH_EXPIRED", 

2264 91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED", 

2265 92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET", 

2266 93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS", 

2267 # RFC8636 

2268 100: "KDC_ERR_NO_ACCEPTABLE_KDF", 

2269 }, 

2270 explicit_tag=0xA6, 

2271 ), 

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

2273 ASN1F_optional( 

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

2275 ), 

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

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

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

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

2280 ), 

2281 implicit_tag=ASN1_Class_KRB.ERROR, 

2282 ) 

2283 

2284 def getSPN(self): 

2285 return "%s@%s" % ( 

2286 self.sname.toString(), 

2287 self.realm.val.decode(), 

2288 ) 

2289 

2290 

2291# PA-FX-ERROR 

2292_PADATA_CLASSES[137] = KRB_ERROR 

2293 

2294 

2295# [MS-KILE] sect 2.2.1 

2296 

2297 

2298class KERB_EXT_ERROR(Packet): 

2299 fields_desc = [ 

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

2301 XLEIntField("reserved", 0), 

2302 XLEIntField("flags", 0x00000001), 

2303 ] 

2304 

2305 

2306# [MS-KILE] sect 2.2.2 

2307 

2308 

2309class _Error_Field(ASN1F_STRING_PacketField): 

2310 def m2i(self, pkt, s): 

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

2312 if not val[0].val: 

2313 return val 

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

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

2316 return val 

2317 

2318 

2319class KERB_ERROR_DATA(ASN1_Packet): 

2320 ASN1_codec = ASN1_Codecs.BER 

2321 ASN1_root = ASN1F_SEQUENCE( 

2322 ASN1F_enum_INTEGER( 

2323 "dataType", 

2324 2, 

2325 { 

2326 1: "KERB_AP_ERR_TYPE_NTSTATUS", # from the wdk 

2327 2: "KERB_AP_ERR_TYPE_SKEW_RECOVERY", 

2328 3: "KERB_ERR_TYPE_EXTENDED", 

2329 }, 

2330 explicit_tag=0xA1, 

2331 ), 

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

2333 ) 

2334 

2335 

2336# This looks like an undocumented structure. 

2337 

2338 

2339class KERB_ERROR_UNK(ASN1_Packet): 

2340 ASN1_codec = ASN1_Codecs.BER 

2341 ASN1_root = ASN1F_SEQUENCE( 

2342 ASN1F_SEQUENCE( 

2343 ASN1F_enum_INTEGER( 

2344 "dataType", 

2345 0, 

2346 { 

2347 -128: "KDC_ERR_MUST_USE_USER2USER", 

2348 }, 

2349 explicit_tag=0xA0, 

2350 ), 

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

2352 ) 

2353 ) 

2354 

2355 

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

2357 

2358 

2359class KRB_TGT_REQ(ASN1_Packet): 

2360 ASN1_codec = ASN1_Codecs.BER 

2361 ASN1_root = ASN1F_SEQUENCE( 

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

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

2364 ASN1F_optional( 

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

2366 ), 

2367 ASN1F_optional( 

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

2369 ), 

2370 ) 

2371 

2372 

2373class KRB_TGT_REP(ASN1_Packet): 

2374 ASN1_codec = ASN1_Codecs.BER 

2375 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

2379 ) 

2380 

2381 

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

2383 

2384 

2385class KRB_FINISHED(ASN1_Packet): 

2386 ASN1_codec = ASN1_Codecs.BER 

2387 ASN1_root = ASN1F_SEQUENCE( 

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

2389 ) 

2390 

2391 

2392# RFC 6542 sect 3.1 

2393 

2394 

2395class KRB_GSS_EXT(Packet): 

2396 fields_desc = [ 

2397 IntEnumField( 

2398 "type", 

2399 0, 

2400 { 

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

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

2403 0x00000001: "GSS_EXTS_IAKERB_FINISHED", # not standard 

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

2405 }, 

2406 ), 

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

2408 MultipleTypeField( 

2409 [ 

2410 ( 

2411 PacketField("data", KRB_FINISHED(), KRB_FINISHED), 

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

2413 ), 

2414 ], 

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

2416 ), 

2417 ] 

2418 

2419 

2420# RFC 4121 sect 4.1.1 

2421 

2422 

2423class KRB_AuthenticatorChecksum(Packet): 

2424 fields_desc = [ 

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

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

2427 FlagsField( 

2428 "Flags", 

2429 0, 

2430 -32, 

2431 { 

2432 0x01: "GSS_C_DELEG_FLAG", 

2433 0x02: "GSS_C_MUTUAL_FLAG", 

2434 0x04: "GSS_C_REPLAY_FLAG", 

2435 0x08: "GSS_C_SEQUENCE_FLAG", 

2436 0x10: "GSS_C_CONF_FLAG", # confidentiality 

2437 0x20: "GSS_C_INTEG_FLAG", # integrity 

2438 # RFC4757 

2439 0x1000: "GSS_C_DCE_STYLE", 

2440 0x2000: "GSS_C_IDENTIFY_FLAG", 

2441 0x4000: "GSS_C_EXTENDED_ERROR_FLAG", 

2442 }, 

2443 ), 

2444 ConditionalField( 

2445 LEShortField("DlgOpt", 1), 

2446 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2447 ), 

2448 ConditionalField( 

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

2450 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2451 ), 

2452 ConditionalField( 

2453 PacketLenField( 

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

2455 ), 

2456 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2457 ), 

2458 # Extensions: RFC 6542 sect 3.1 

2459 PacketListField("Exts", KRB_GSS_EXT(), KRB_GSS_EXT), 

2460 ] 

2461 

2462 

2463# Kerberos V5 GSS-API - RFC1964 and RFC4121 

2464 

2465_TOK_IDS = { 

2466 # RFC 1964 

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

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

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

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

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

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

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

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

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

2476 # RFC 4121 

2477 b"\x04\x04": "GSS_GetMIC", 

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

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

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

2481} 

2482_SGN_ALGS = { 

2483 0x00: "DES MAC MD5", 

2484 0x01: "MD2.5", 

2485 0x02: "DES MAC", 

2486 # RFC 4757 

2487 0x11: "HMAC", 

2488} 

2489_SEAL_ALGS = { 

2490 0: "DES", 

2491 0xFFFF: "none", 

2492 # RFC 4757 

2493 0x10: "RC4", 

2494} 

2495 

2496 

2497# RFC 1964 - sect 1.1 

2498 

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

2500_InitialContextTokens = {} # filled below 

2501 

2502 

2503class KRB_InnerToken(Packet): 

2504 name = "Kerberos v5 InnerToken" 

2505 fields_desc = [ 

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

2507 PacketField( 

2508 "root", 

2509 KRB_AP_REQ(), 

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

2511 ), 

2512 ] 

2513 

2514 def mysummary(self): 

2515 return self.sprintf( 

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

2517 ) 

2518 

2519 def guess_payload_class(self, payload): 

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

2521 return conf.padding_layer 

2522 return Kerberos 

2523 

2524 @classmethod 

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

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

2527 # Older RFC1964 variants of the token have KRB_GSSAPI_Token wrapper 

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

2529 return KRB_GSSAPI_Token 

2530 return cls 

2531 

2532 

2533# RFC 4121 - sect 4.1 

2534 

2535 

2536class KRB_GSSAPI_Token(GSSAPI_BLOB): 

2537 name = "Kerberos GSSAPI-Token" 

2538 ASN1_codec = ASN1_Codecs.BER 

2539 ASN1_root = ASN1F_SEQUENCE( 

2540 ASN1F_OID("MechType", "1.2.840.113554.1.2.2"), 

2541 ASN1F_PACKET( 

2542 "innerToken", 

2543 KRB_InnerToken(), 

2544 KRB_InnerToken, 

2545 implicit_tag=0x0, 

2546 ), 

2547 implicit_tag=ASN1_Class_KRB.Token, 

2548 ) 

2549 

2550 

2551# RFC 1964 - sect 1.2.1 

2552 

2553 

2554class KRB_GSS_MIC_RFC1964(Packet): 

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

2556 fields_desc = [ 

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

2558 XLEIntField("Filler", 0xFFFFFFFF), 

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

2560 PadField( # sect 1.2.2.3 

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

2562 align=8, 

2563 padwith=b"\x04", 

2564 ), 

2565 ] 

2566 

2567 def default_payload_class(self, payload): 

2568 return conf.padding_layer 

2569 

2570 

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

2572 

2573# RFC 1964 - sect 1.2.2 

2574 

2575 

2576class KRB_GSS_Wrap_RFC1964(Packet): 

2577 name = "Kerberos v5 GSS_Wrap (RFC1964)" 

2578 fields_desc = [ 

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

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

2581 XLEShortField("Filler", 0xFFFF), 

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

2583 PadField( # sect 1.2.2.3 

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

2585 align=8, 

2586 padwith=b"\x04", 

2587 ), 

2588 # sect 1.2.2.3 

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

2590 ] 

2591 

2592 def default_payload_class(self, payload): 

2593 return conf.padding_layer 

2594 

2595 

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

2597 

2598 

2599# RFC 1964 - sect 1.2.2 

2600 

2601 

2602class KRB_GSS_Delete_sec_context_RFC1964(Packet): 

2603 name = "Kerberos v5 GSS_Delete_sec_context (RFC1964)" 

2604 fields_desc = KRB_GSS_MIC_RFC1964.fields_desc 

2605 

2606 

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

2608 

2609 

2610# RFC 4121 - sect 4.2.2 

2611_KRB5_GSS_Flags = [ 

2612 "SentByAcceptor", 

2613 "Sealed", 

2614 "AcceptorSubkey", 

2615] 

2616 

2617 

2618# RFC 4121 - sect 4.2.6.1 

2619 

2620 

2621class KRB_GSS_MIC(Packet): 

2622 name = "Kerberos v5 MIC Token" 

2623 fields_desc = [ 

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

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

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

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

2628 ] 

2629 

2630 def default_payload_class(self, payload): 

2631 return conf.padding_layer 

2632 

2633 

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

2635 

2636 

2637# RFC 4121 - sect 4.2.6.2 

2638 

2639 

2640class KRB_GSS_Wrap(Packet): 

2641 name = "Kerberos v5 Wrap Token" 

2642 fields_desc = [ 

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

2644 XByteField("Filler", 0xFF), 

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

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

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

2648 MultipleTypeField( 

2649 [ 

2650 ( 

2651 XStrField("Data", b""), 

2652 lambda pkt: pkt.Flags.Sealed, 

2653 ) 

2654 ], 

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

2656 ), 

2657 ] 

2658 

2659 def default_payload_class(self, payload): 

2660 return conf.padding_layer 

2661 

2662 

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

2664 

2665 

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

2667 

2668 

2669class IAKERB_HEADER(ASN1_Packet): 

2670 ASN1_codec = ASN1_Codecs.BER 

2671 ASN1_root = ASN1F_SEQUENCE( 

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

2673 ASN1F_optional( 

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

2675 ), 

2676 ) 

2677 

2678 

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

2680 

2681 

2682# Register for GSSAPI 

2683 

2684# Kerberos 5 

2685_GSSAPI_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2686_GSSAPI_SIGNATURE_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2687# Kerberos 5 - U2U 

2688_GSSAPI_OIDS["1.2.840.113554.1.2.2.3"] = KRB_InnerToken 

2689# Kerberos 5 - IAKERB 

2690_GSSAPI_OIDS["1.3.6.1.5.2.5"] = KRB_InnerToken 

2691 

2692 

2693# Entry class 

2694 

2695# RFC4120 sect 5.10 

2696 

2697 

2698class Kerberos(ASN1_Packet): 

2699 ASN1_codec = ASN1_Codecs.BER 

2700 ASN1_root = ASN1F_CHOICE( 

2701 "root", 

2702 None, 

2703 # RFC4120 

2704 KRB_GSSAPI_Token, # [APPLICATION 0] 

2705 KRB_Ticket, # [APPLICATION 1] 

2706 KRB_Authenticator, # [APPLICATION 2] 

2707 KRB_AS_REQ, # [APPLICATION 10] 

2708 KRB_AS_REP, # [APPLICATION 11] 

2709 KRB_TGS_REQ, # [APPLICATION 12] 

2710 KRB_TGS_REP, # [APPLICATION 13] 

2711 KRB_AP_REQ, # [APPLICATION 14] 

2712 KRB_AP_REP, # [APPLICATION 15] 

2713 # RFC4120 

2714 KRB_ERROR, # [APPLICATION 30] 

2715 ) 

2716 

2717 def mysummary(self): 

2718 return self.root.summary() 

2719 

2720 

2721bind_bottom_up(UDP, Kerberos, sport=88) 

2722bind_bottom_up(UDP, Kerberos, dport=88) 

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

2724 

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

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

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

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

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

2730 

2731 

2732# RFC4120 sect 7.2.2 

2733 

2734 

2735class KerberosTCPHeader(Packet): 

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

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

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

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

2740 

2741 @classmethod 

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

2743 if len(data) < 4: 

2744 return None 

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

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

2747 return cls(data) 

2748 

2749 

2750bind_layers(KerberosTCPHeader, Kerberos) 

2751 

2752bind_bottom_up(TCP, KerberosTCPHeader, sport=88) 

2753bind_layers(TCP, KerberosTCPHeader, dport=88) 

2754 

2755 

2756# RFC3244 sect 2 

2757 

2758 

2759class KPASSWD_REQ(Packet): 

2760 fields_desc = [ 

2761 ShortField("len", None), 

2762 ShortField("pvno", 0xFF80), 

2763 ShortField("apreqlen", None), 

2764 PacketLenField( 

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

2766 ), 

2767 ConditionalField( 

2768 PacketLenField( 

2769 "krbpriv", 

2770 KRB_PRIV(), 

2771 KRB_PRIV, 

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

2773 ), 

2774 lambda pkt: pkt.apreqlen != 0, 

2775 ), 

2776 ConditionalField( 

2777 PacketLenField( 

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

2779 ), 

2780 lambda pkt: pkt.apreqlen == 0, 

2781 ), 

2782 ] 

2783 

2784 def post_build(self, p, pay): 

2785 if self.len is None: 

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

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

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

2789 return p + pay 

2790 

2791 

2792class ChangePasswdData(ASN1_Packet): 

2793 ASN1_codec = ASN1_Codecs.BER 

2794 ASN1_root = ASN1F_SEQUENCE( 

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

2796 ASN1F_optional( 

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

2798 ), 

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

2800 ) 

2801 

2802 

2803class KPASSWD_REP(Packet): 

2804 fields_desc = [ 

2805 ShortField("len", None), 

2806 ShortField("pvno", 0x0001), 

2807 ShortField("apreplen", None), 

2808 PacketLenField( 

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

2810 ), 

2811 ConditionalField( 

2812 PacketLenField( 

2813 "krbpriv", 

2814 KRB_PRIV(), 

2815 KRB_PRIV, 

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

2817 ), 

2818 lambda pkt: pkt.apreplen != 0, 

2819 ), 

2820 ConditionalField( 

2821 PacketLenField( 

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

2823 ), 

2824 lambda pkt: pkt.apreplen == 0, 

2825 ), 

2826 ] 

2827 

2828 def post_build(self, p, pay): 

2829 if self.len is None: 

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

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

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

2833 return p + pay 

2834 

2835 def answers(self, other): 

2836 return isinstance(other, KPASSWD_REQ) 

2837 

2838 

2839KPASSWD_RESULTS = { 

2840 0: "KRB5_KPASSWD_SUCCESS", 

2841 1: "KRB5_KPASSWD_MALFORMED", 

2842 2: "KRB5_KPASSWD_HARDERROR", 

2843 3: "KRB5_KPASSWD_AUTHERROR", 

2844 4: "KRB5_KPASSWD_SOFTERROR", 

2845 5: "KRB5_KPASSWD_ACCESSDENIED", 

2846 6: "KRB5_KPASSWD_BAD_VERSION", 

2847 7: "KRB5_KPASSWD_INITIAL_FLAG_NEEDED", 

2848} 

2849 

2850 

2851class KPasswdRepData(Packet): 

2852 fields_desc = [ 

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

2854 StrField("resultString", ""), 

2855 ] 

2856 

2857 

2858class Kpasswd(Packet): 

2859 @classmethod 

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

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

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

2863 return KPASSWD_REQ 

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

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

2866 if asn1_tag == 14: 

2867 return KPASSWD_REQ 

2868 elif asn1_tag == 15: 

2869 return KPASSWD_REP 

2870 return KPASSWD_REQ 

2871 

2872 

2873bind_bottom_up(UDP, Kpasswd, sport=464) 

2874bind_bottom_up(UDP, Kpasswd, dport=464) 

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

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

2877 

2878 

2879class KpasswdTCPHeader(Packet): 

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

2881 

2882 @classmethod 

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

2884 if len(data) < 4: 

2885 return None 

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

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

2888 return cls(data) 

2889 

2890 

2891bind_layers(KpasswdTCPHeader, Kpasswd) 

2892 

2893bind_bottom_up(TCP, KpasswdTCPHeader, sport=464) 

2894bind_layers(TCP, KpasswdTCPHeader, dport=464) 

2895 

2896# [MS-KKDCP] 

2897 

2898 

2899class _KerbMessage_Field(ASN1F_STRING_PacketField): 

2900 def m2i(self, pkt, s): 

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

2902 if not val[0].val: 

2903 return val 

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

2905 

2906 

2907class KDC_PROXY_MESSAGE(ASN1_Packet): 

2908 ASN1_codec = ASN1_Codecs.BER 

2909 ASN1_root = ASN1F_SEQUENCE( 

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

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

2912 ASN1F_optional( 

2913 ASN1F_FLAGS( 

2914 "dclocatorHint", 

2915 None, 

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

2917 explicit_tag=0xA2, 

2918 ) 

2919 ), 

2920 ) 

2921 

2922 

2923class KdcProxySocket(SuperSocket): 

2924 """ 

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

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

2927 """ 

2928 

2929 def __init__( 

2930 self, 

2931 url, 

2932 targetDomain, 

2933 dclocatorHint=None, 

2934 no_check_certificate=False, 

2935 **kwargs, 

2936 ): 

2937 self.url = url 

2938 self.targetDomain = targetDomain 

2939 self.dclocatorHint = dclocatorHint 

2940 self.no_check_certificate = no_check_certificate 

2941 self.queue = deque() 

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

2943 

2944 def recv(self, x=None): 

2945 return self.queue.popleft() 

2946 

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

2948 from scapy.layers.http import HTTP_Client 

2949 

2950 cli = HTTP_Client(no_check_certificate=self.no_check_certificate) 

2951 try: 

2952 # sr it via the web client 

2953 resp = cli.request( 

2954 self.url, 

2955 Method="POST", 

2956 data=bytes( 

2957 # Wrap request in KDC_PROXY_MESSAGE 

2958 KDC_PROXY_MESSAGE( 

2959 kerbMessage=bytes(x), 

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

2961 # dclocatorHint is optional 

2962 dclocatorHint=self.dclocatorHint, 

2963 ) 

2964 ), 

2965 http_headers={ 

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

2967 "Pragma": "no-cache", 

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

2969 }, 

2970 ) 

2971 if resp and conf.raw_layer in resp: 

2972 # Parse the payload 

2973 resp = KDC_PROXY_MESSAGE(resp.load).kerbMessage 

2974 # We have an answer, queue it. 

2975 self.queue.append(resp) 

2976 else: 

2977 raise EOFError 

2978 finally: 

2979 cli.close() 

2980 

2981 @staticmethod 

2982 def select(sockets, remain=None): 

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

2984 

2985 

2986# Util functions 

2987 

2988 

2989class PKINIT_KEX_METHOD(IntEnum): 

2990 DIFFIE_HELLMAN = 1 

2991 PUBLIC_KEY = 2 

2992 

2993 

2994class KerberosClient(Automaton): 

2995 """ 

2996 Implementation of a Kerberos client. 

2997 

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

2999 wrap this client. 

3000 

3001 Common parameters: 

3002 

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

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

3005 :param upn: the UPN of the client. 

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

3007 :param password: the password of the client. 

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

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

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

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

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

3013 

3014 Advanced common parameters: 

3015 

3016 :param kdc_proxy: specify a KDC proxy url 

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

3018 :param fast: use FAST armoring 

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

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

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

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

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

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

3025 

3026 AS-REQ only: 

3027 

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

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

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

3031 only the ROOT CA is required. 

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

3033 'password' is the password of the p12. 

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

3035 Certificate based one for PKINIT. 

3036 

3037 TGS-REQ only: 

3038 

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

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

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

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

3043 :param u2u: sets the U2U flag 

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

3045 :param s4u2proxy: sets the S4U2Proxy flag 

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

3047 """ 

3048 

3049 RES_AS_MODE = namedtuple( 

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

3051 ) 

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

3053 

3054 class MODE(IntEnum): 

3055 AS_REQ = 0 

3056 TGS_REQ = 1 

3057 GET_SALT = 2 

3058 

3059 def __init__( 

3060 self, 

3061 mode=MODE.AS_REQ, 

3062 ip: Optional[str] = None, 

3063 upn: Optional[str] = None, 

3064 canonicalize: bool = False, 

3065 password: Optional[str] = None, 

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

3067 realm: Optional[str] = None, 

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

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

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

3071 no_verify_cert: bool = False, 

3072 p12: Optional[str] = None, 

3073 spn: Optional[str] = None, 

3074 ticket: Optional[KRB_Ticket] = None, 

3075 host: Optional[str] = None, 

3076 renew: bool = False, 

3077 additional_tickets: List[KRB_Ticket] = [], 

3078 u2u: bool = False, 

3079 for_user: Optional[str] = None, 

3080 s4u2proxy: bool = False, 

3081 dmsa: bool = False, 

3082 kdc_proxy: Optional[str] = None, 

3083 kdc_proxy_no_check_certificate: bool = False, 

3084 fast: bool = False, 

3085 armor_ticket: KRB_Ticket = None, 

3086 armor_ticket_upn: Optional[str] = None, 

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

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

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

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

3091 pkinit_kex_method: PKINIT_KEX_METHOD = PKINIT_KEX_METHOD.DIFFIE_HELLMAN, 

3092 port: int = 88, 

3093 timeout: int = 5, 

3094 verbose: bool = True, 

3095 **kwargs, 

3096 ): 

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

3098 from scapy.layers.ldap import dclocator 

3099 

3100 # PKINIT checks 

3101 if p12 is not None: 

3102 # password should be None or bytes 

3103 if isinstance(password, str): 

3104 password = password.encode() 

3105 

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

3107 # retry once. 

3108 while True: 

3109 try: 

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

3111 x509key, x509, _ = pkcs12.load_key_and_certificates( 

3112 fd.read(), 

3113 password=password, 

3114 ) 

3115 break 

3116 except ValueError as ex: 

3117 if password is None: 

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

3119 try: 

3120 from prompt_toolkit import prompt 

3121 

3122 password = prompt( 

3123 "Enter PKCS12 password: ", is_password=True 

3124 ) 

3125 except ImportError: 

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

3127 password = password.encode() 

3128 else: 

3129 raise ex 

3130 

3131 x509 = Cert(cryptography_obj=x509) 

3132 x509key = PrivKey(cryptography_obj=x509key) 

3133 elif x509 and x509key: 

3134 if not isinstance(x509, Cert): 

3135 x509 = Cert(x509) 

3136 if not isinstance(x509key, PrivKey): 

3137 x509key = PrivKey(x509key) 

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

3139 ca = CertList(ca) 

3140 if upn is None and x509: 

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

3142 if realm is None: 

3143 raise ValueError( 

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

3145 ) 

3146 for ext in x509.extensions: 

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

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

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

3150 break 

3151 if upn is None: 

3152 raise ValueError( 

3153 "Could not find subjectAltName in certificate !" 

3154 " Please provide a UPN." 

3155 ) 

3156 canonicalize = True 

3157 

3158 # UPN, SPN and realm calculation 

3159 if not upn: 

3160 raise ValueError("Invalid upn") 

3161 if realm is None: 

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

3163 _, realm = _parse_upn(upn) 

3164 elif mode == self.MODE.TGS_REQ: 

3165 _, realm = _parse_spn(spn) 

3166 if not realm and ticket: 

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

3168 # of the ticket. 

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

3170 else: 

3171 raise ValueError("Invalid realm") 

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

3173 spn = "krbtgt/" + realm 

3174 elif not spn: 

3175 raise ValueError("Invalid spn") 

3176 

3177 # Extra checks for specific requests 

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

3179 if not host: 

3180 raise ValueError("Invalid host") 

3181 if x509 is not None: 

3182 if x509key and not ca: 

3183 if not no_verify_cert: 

3184 raise ValueError( 

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

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

3187 ) 

3188 else: 

3189 ca = [] 

3190 elif not x509key or not ca: 

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

3192 elif mode == self.MODE.TGS_REQ: 

3193 if not ticket: 

3194 raise ValueError("Invalid ticket") 

3195 

3196 if not ip and not kdc_proxy: 

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

3198 ip = dclocator( 

3199 realm, 

3200 timeout=timeout, 

3201 # Use connect mode instead of ldap for compatibility 

3202 # with MIT kerberos servers 

3203 mode="connect", 

3204 port=port, 

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

3206 ).ip 

3207 

3208 # Armoring checks 

3209 if fast: 

3210 if mode == self.MODE.AS_REQ: 

3211 # Requires an external ticket 

3212 if not armor_ticket or not armor_ticket_upn or not armor_ticket_skey: 

3213 raise ValueError( 

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

3215 "please provide the 3 required armor arguments" 

3216 ) 

3217 elif mode == self.MODE.TGS_REQ: 

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

3219 raise ValueError( 

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

3221 ) 

3222 

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

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

3225 if mode == self.MODE.GET_SALT: 

3226 if etypes is not None: 

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

3228 

3229 etypes = [ 

3230 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3231 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3232 ] 

3233 elif etypes is None: 

3234 etypes = [ 

3235 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3236 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3237 EncryptionType.RC4_HMAC, 

3238 EncryptionType.DES_CBC_MD5, 

3239 ] 

3240 self.etypes = etypes 

3241 

3242 self.mode = mode 

3243 

3244 self.result = None # Result 

3245 

3246 self._timeout = timeout 

3247 self._verbose = verbose 

3248 self._ip = ip 

3249 self._port = port 

3250 self.kdc_proxy = kdc_proxy 

3251 self.kdc_proxy_no_check_certificate = kdc_proxy_no_check_certificate 

3252 

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

3254 self.host = host.upper() 

3255 self.password = password and bytes_encode(password) 

3256 self.spn = spn 

3257 self.upn = upn 

3258 self.canonicalize = canonicalize # Whether we request canonicalization 

3259 self.realm = realm.upper() 

3260 self.x509 = x509 

3261 self.x509key = x509key 

3262 self.pkinit_kex_method = pkinit_kex_method 

3263 self.ticket = ticket 

3264 self.fast = fast 

3265 self.armor_ticket = armor_ticket 

3266 self.armor_ticket_upn = armor_ticket_upn 

3267 self.armor_ticket_skey = armor_ticket_skey 

3268 self.key_list_req = key_list_req 

3269 self.renew = renew 

3270 self.additional_tickets = additional_tickets # U2U + S4U2Proxy 

3271 self.u2u = u2u # U2U 

3272 self.for_user = for_user # FOR-USER 

3273 self.s4u2proxy = s4u2proxy # S4U2Proxy 

3274 self.dmsa = dmsa # DMSA 

3275 self.key = key 

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

3277 self.replykey = None # Key used for reply 

3278 # See RFC4120 - sect 7.2.2 

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

3280 self.should_followup = False 

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

3282 self.fast_req_sent = False 

3283 # Session parameters 

3284 if self.x509: 

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

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

3287 self.pre_auth = True 

3288 else: 

3289 self.pre_auth = False 

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

3291 self.fast_rep = None 

3292 self.fast_error = None 

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

3294 self.fast_armorkey = None # The armor key 

3295 self.fxcookie = None 

3296 self.pkinit_dh_key = None 

3297 self.no_verify_cert = no_verify_cert 

3298 if ca is not None: 

3299 self.pkinit_cms = CMS_Engine(ca) 

3300 else: 

3301 self.pkinit_cms = None 

3302 if dhashes is None: 

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

3304 else: 

3305 self.dhashes = dhashes 

3306 

3307 # Launch the client 

3308 sock = self._connect() 

3309 super(KerberosClient, self).__init__( 

3310 sock=sock, 

3311 **kwargs, 

3312 ) 

3313 

3314 def _connect(self): 

3315 """ 

3316 Internal function to bind a socket to the DC. 

3317 This also takes care of an eventual KDC proxy. 

3318 """ 

3319 if self.kdc_proxy: 

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

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

3322 sock = KdcProxySocket( 

3323 url=self.kdc_proxy, 

3324 targetDomain=self.realm, 

3325 no_check_certificate=self.kdc_proxy_no_check_certificate, 

3326 ) 

3327 else: 

3328 sock = socket.socket() 

3329 sock.settimeout(self._timeout) 

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

3331 sock = StreamSocket(sock, KerberosTCPHeader) 

3332 return sock 

3333 

3334 def send(self, pkt): 

3335 """ 

3336 Sends a wrapped Kerberos packet 

3337 """ 

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

3339 

3340 def _show_krb_error(self, error): 

3341 """ 

3342 Displays a Kerberos error 

3343 """ 

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

3345 # KDC_ERR_S_PRINCIPAL_UNKNOWN 

3346 if ( 

3347 isinstance(error.root.eData, KERB_ERROR_UNK) 

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

3349 ): 

3350 log_runtime.error( 

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

3352 ) 

3353 else: 

3354 log_runtime.error( 

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

3356 % error.root.getSPN() 

3357 ) 

3358 else: 

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

3360 if self._verbose: 

3361 error.show() 

3362 

3363 def _base_kdc_req(self, now_time): 

3364 """ 

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

3366 """ 

3367 kdcreq = KRB_KDC_REQ_BODY( 

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

3369 additionalTickets=None, 

3370 # Windows default 

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

3372 cname=None, 

3373 realm=ASN1_GENERAL_STRING(self.realm), 

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

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

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

3377 ) 

3378 if self.renew: 

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

3380 return kdcreq 

3381 

3382 def calc_fast_armorkey(self): 

3383 """ 

3384 Calculate and return the FAST armorkey 

3385 """ 

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

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

3388 # AS-REQ mode 

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

3390 

3391 self.fast_armorkey = KRB_FX_CF2( 

3392 self.fast_skey, 

3393 self.armor_ticket_skey, 

3394 b"subkeyarmor", 

3395 b"ticketarmor", 

3396 ) 

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

3398 # TGS-REQ: 2 cases 

3399 

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

3401 

3402 if not self.armor_ticket: 

3403 # Case 1: Implicit armoring 

3404 self.fast_armorkey = KRB_FX_CF2( 

3405 self.subkey, 

3406 self.key, 

3407 b"subkeyarmor", 

3408 b"ticketarmor", 

3409 ) 

3410 else: 

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

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

3413 

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

3415 

3416 explicit_armor_key = KRB_FX_CF2( 

3417 self.fast_skey, 

3418 self.armor_ticket_skey, 

3419 b"subkeyarmor", 

3420 b"ticketarmor", 

3421 ) 

3422 

3423 self.fast_armorkey = KRB_FX_CF2( 

3424 explicit_armor_key, 

3425 self.subkey, 

3426 b"explicitarmor", 

3427 b"tgsarmor", 

3428 ) 

3429 

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

3431 """ 

3432 :param kdc_req: the KDC_REQ_BODY to wrap 

3433 :param padata: the list of PADATA to wrap 

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

3435 """ 

3436 

3437 # Create the PA Fast request wrapper 

3438 pafastreq = PA_FX_FAST_REQUEST( 

3439 armoredData=KrbFastArmoredReq( 

3440 reqChecksum=Checksum(), 

3441 encFastReq=EncryptedData(), 

3442 ) 

3443 ) 

3444 

3445 if self.armor_ticket is not None: 

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

3447 

3448 pafastreq.armoredData.armor = KrbFastArmor( 

3449 armorType=1, # FX_FAST_ARMOR_AP_REQUEST 

3450 armorValue=KRB_AP_REQ( 

3451 ticket=self.armor_ticket, 

3452 authenticator=EncryptedData(), 

3453 ), 

3454 ) 

3455 

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

3457 _, crealm = _parse_upn(self.armor_ticket_upn) 

3458 authenticator = KRB_Authenticator( 

3459 crealm=ASN1_GENERAL_STRING(crealm), 

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

3461 cksum=None, 

3462 ctime=ASN1_GENERALIZED_TIME(now_time), 

3463 cusec=ASN1_INTEGER(0), 

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

3465 seqNumber=ASN1_INTEGER(0), 

3466 encAuthorizationData=None, 

3467 ) 

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

3469 self.armor_ticket_skey, 

3470 authenticator, 

3471 ) 

3472 

3473 # Sign the fast request wrapper 

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

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

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

3477 pafastreq.armoredData.reqChecksum.make( 

3478 self.fast_armorkey, 

3479 bytes(pa_tgsreq_ap), 

3480 ) 

3481 else: 

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

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

3484 # containing message" 

3485 pafastreq.armoredData.reqChecksum.make( 

3486 self.fast_armorkey, 

3487 bytes(kdc_req), 

3488 ) 

3489 

3490 # Build and encrypt the Fast request 

3491 fastreq = KrbFastReq( 

3492 padata=padata, 

3493 reqBody=kdc_req, 

3494 ) 

3495 pafastreq.armoredData.encFastReq.encrypt( 

3496 self.fast_armorkey, 

3497 fastreq, 

3498 ) 

3499 

3500 # Return the PADATA 

3501 return PADATA( 

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

3503 padataValue=pafastreq, 

3504 ) 

3505 

3506 def as_req(self): 

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

3508 

3509 # 1. Build and populate KDC-REQ 

3510 kdc_req = self._base_kdc_req(now_time=now_time) 

3511 kdc_req.addresses = [ 

3512 HostAddress( 

3513 addrType=ASN1_INTEGER(20), # Netbios 

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

3515 ) 

3516 ] 

3517 kdc_req.addresses = None 

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

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

3520 

3521 # 2. Build the list of PADATA 

3522 padata = [ 

3523 PADATA( 

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

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

3526 ) 

3527 ] 

3528 

3529 # Cookie support 

3530 if self.fxcookie: 

3531 padata.insert( 

3532 0, 

3533 PADATA( 

3534 padataType=133, # PA-FX-COOKIE 

3535 padataValue=self.fxcookie, 

3536 ), 

3537 ) 

3538 

3539 # FAST 

3540 if self.fast: 

3541 # Calculate the armor key 

3542 self.calc_fast_armorkey() 

3543 

3544 # [MS-KILE] sect 3.2.5.5 

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

3546 padata.append( 

3547 PADATA( 

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

3549 padataValue=PA_PAC_OPTIONS( 

3550 options="Claims", 

3551 ), 

3552 ) 

3553 ) 

3554 

3555 # Pre-auth is requested 

3556 if self.pre_auth: 

3557 if self.x509: 

3558 # Special PKINIT (RFC4556) factor 

3559 

3560 # RFC4556 - 3.2.1. Generation of Client Request 

3561 

3562 # RFC4556 - 3.2.1 - (5) AuthPack 

3563 authpack = KRB_AuthPack( 

3564 pkAuthenticator=KRB_PKAuthenticator( 

3565 ctime=ASN1_GENERALIZED_TIME(now_time), 

3566 cusec=ASN1_INTEGER(0), 

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

3568 ), 

3569 clientPublicValue=None, # Used only in DH mode 

3570 supportedCMSTypes=[], 

3571 clientDHNonce=None, 

3572 supportedKDFs=None, 

3573 ) 

3574 

3575 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

3576 # RFC4556 - 3.2.3.1. Diffie-Hellman Key Exchange 

3577 

3578 # We (and Windows) use modp2048 

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

3580 self.pkinit_dh_key = dh_parameters.generate_private_key() 

3581 numbers = dh_parameters.parameter_numbers() 

3582 

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

3584 # and we want the DomainParameters format. 

3585 authpack.clientPublicValue = X509_SubjectPublicKeyInfo( 

3586 signatureAlgorithm=X509_AlgorithmIdentifier( 

3587 algorithm=ASN1_OID("dhpublicnumber"), 

3588 parameters=DomainParameters( 

3589 p=ASN1_INTEGER(numbers.p), 

3590 g=ASN1_INTEGER(numbers.g), 

3591 # q: see ERRATA 1 of RFC4556 

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

3593 j=None, 

3594 ), 

3595 ), 

3596 subjectPublicKey=DHPublicKey( 

3597 y=ASN1_INTEGER( 

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

3599 ), 

3600 ), 

3601 ) 

3602 elif self.pkinit_kex_method == PKINIT_KEX_METHOD.PUBLIC_KEY: 

3603 # RFC4556 - 3.2.3.2. - Public Key Encryption 

3604 

3605 # Set supportedCMSTypes, supportedKDFs 

3606 authpack.supportedCMSTypes = [ 

3607 X509_AlgorithmIdentifier(algorithm=ASN1_OID(x)) 

3608 for x in [ 

3609 "ecdsa-with-SHA512", 

3610 "ecdsa-with-SHA256", 

3611 "sha512WithRSAEncryption", 

3612 "sha256WithRSAEncryption", 

3613 ] 

3614 ] 

3615 authpack.supportedKDFs = [ 

3616 KDFAlgorithmId(kdfId=ASN1_OID(x)) 

3617 for x in [ 

3618 "id-pkinit-kdf-sha256", 

3619 "id-pkinit-kdf-sha1", 

3620 "id-pkinit-kdf-sha512", 

3621 ] 

3622 ] 

3623 

3624 # XXX UNFINISHED 

3625 raise NotImplementedError 

3626 else: 

3627 raise ValueError 

3628 

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

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

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

3632 

3633 # Populate paChecksum 

3634 authpack.pkAuthenticator.make_checksum( 

3635 bytes(kdc_req), 

3636 h=dhash, 

3637 ) 

3638 

3639 # Sign the AuthPack 

3640 signedAuthpack = self.pkinit_cms.sign( 

3641 authpack, 

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

3643 self.x509, 

3644 self.x509key, 

3645 dhash=dhash, 

3646 ) 

3647 

3648 # Build PA-DATA 

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

3650 pafactor = PADATA( 

3651 padataType=self.pa_type, 

3652 padataValue=PA_PK_AS_REQ( 

3653 signedAuthpack=signedAuthpack, 

3654 trustedCertifiers=None, 

3655 kdcPkId=None, 

3656 ), 

3657 ) 

3658 

3659 # RFC 4557 extension - OCSP 

3660 padata.insert( 

3661 0, 

3662 PADATA( 

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

3664 ), 

3665 ) 

3666 else: 

3667 # Key-based factor 

3668 

3669 if self.fast: 

3670 # Special FAST factor 

3671 # RFC6113 sect 5.4.6 

3672 

3673 # Calculate the 'challenge key' 

3674 ts_key = KRB_FX_CF2( 

3675 self.fast_armorkey, 

3676 self.key, 

3677 b"clientchallengearmor", 

3678 b"challengelongterm", 

3679 ) 

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

3681 pafactor = PADATA( 

3682 padataType=self.pa_type, 

3683 padataValue=EncryptedData(), 

3684 ) 

3685 else: 

3686 # Usual 'timestamp' factor 

3687 ts_key = self.key 

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

3689 pafactor = PADATA( 

3690 padataType=self.pa_type, 

3691 padataValue=EncryptedData(), 

3692 ) 

3693 pafactor.padataValue.encrypt( 

3694 ts_key, 

3695 PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), 

3696 ) 

3697 

3698 # Insert Pre-Authentication data 

3699 padata.insert( 

3700 0, 

3701 pafactor, 

3702 ) 

3703 

3704 # FAST support 

3705 if self.fast: 

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

3707 # hidden inside the encrypted section. 

3708 padata = [ 

3709 self._fast_wrap( 

3710 kdc_req=kdc_req, 

3711 padata=padata, 

3712 now_time=now_time, 

3713 ) 

3714 ] 

3715 

3716 # 3. Build the request 

3717 asreq = Kerberos( 

3718 root=KRB_AS_REQ( 

3719 padata=padata, 

3720 reqBody=kdc_req, 

3721 ) 

3722 ) 

3723 

3724 # Note the reply key 

3725 self.replykey = self.key 

3726 

3727 return asreq 

3728 

3729 def tgs_req(self): 

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

3731 

3732 # Compute armor key for FAST 

3733 if self.fast: 

3734 self.calc_fast_armorkey() 

3735 

3736 # 1. Build and populate KDC-REQ 

3737 kdc_req = self._base_kdc_req(now_time=now_time) 

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

3739 

3740 # Additional tickets 

3741 if self.additional_tickets: 

3742 kdc_req.additionalTickets = self.additional_tickets 

3743 

3744 # U2U 

3745 if self.u2u: 

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

3747 

3748 # 2. Build the list of PADATA 

3749 padata = [] 

3750 

3751 # [MS-SFU] FOR-USER extension 

3752 if self.for_user is not None: 

3753 # [MS-SFU] note 4: 

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

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

3756 # certificate is available. 

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

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

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

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

3761 

3762 # 1. Add PA_S4U_X509_USER 

3763 pasfux509 = PA_S4U_X509_USER( 

3764 userId=S4UUserID( 

3765 nonce=kdc_req.nonce, 

3766 # [MS-SFU] note 5: 

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

3768 options="USE_REPLY_KEY_USAGE", 

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

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

3771 subjectCertificate=None, # TODO 

3772 ), 

3773 checksum=Checksum(), 

3774 ) 

3775 

3776 if self.dmsa: 

3777 # DMSA = set UNCONDITIONAL_DELEGATION to 1 

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

3779 

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

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

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

3783 pasfux509.checksum.make( 

3784 self.key, 

3785 bytes(pasfux509.userId), 

3786 cksumtype=ChecksumType.RSA_MD4, 

3787 ) 

3788 else: 

3789 pasfux509.checksum.make( 

3790 self.key, 

3791 bytes(pasfux509.userId), 

3792 ) 

3793 padata.append( 

3794 PADATA( 

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

3796 padataValue=pasfux509, 

3797 ) 

3798 ) 

3799 

3800 # 2. Add PA_FOR_USER 

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

3802 paforuser = PA_FOR_USER( 

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

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

3805 cksum=Checksum(), 

3806 ) 

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

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

3809 ) + ( 

3810 ( 

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

3812 + paforuser.userRealm.val 

3813 + paforuser.authPackage.val 

3814 ).encode() 

3815 ) 

3816 paforuser.cksum.make( 

3817 self.key, 

3818 S4UByteArray, 

3819 cksumtype=ChecksumType.HMAC_MD5, 

3820 ) 

3821 padata.append( 

3822 PADATA( 

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

3824 padataValue=paforuser, 

3825 ) 

3826 ) 

3827 

3828 # [MS-SFU] S4U2proxy - sect 3.1.5.2.1 

3829 if self.s4u2proxy: 

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

3831 padata.append( 

3832 PADATA( 

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

3834 padataValue=PA_PAC_OPTIONS( 

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

3836 ), 

3837 ) 

3838 ) 

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

3840 kdc_req.kdcOptions.set(14, 1) 

3841 

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

3843 if self.key_list_req: 

3844 padata.append( 

3845 PADATA( 

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

3847 padataValue=KERB_KEY_LIST_REQ( 

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

3849 ), 

3850 ) 

3851 ) 

3852 

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

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

3855 pa_tgs_req = PADATA( 

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

3857 padataValue=apreq, 

3858 ) 

3859 

3860 # 4. Populate it's authenticator 

3861 _, crealm = _parse_upn(self.upn) 

3862 authenticator = KRB_Authenticator( 

3863 crealm=ASN1_GENERAL_STRING(crealm), 

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

3865 cksum=None, 

3866 ctime=ASN1_GENERALIZED_TIME(now_time), 

3867 cusec=ASN1_INTEGER(0), 

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

3869 seqNumber=None, 

3870 encAuthorizationData=None, 

3871 ) 

3872 

3873 # Compute checksum 

3874 if self.key.cksumtype: 

3875 authenticator.cksum = Checksum() 

3876 authenticator.cksum.make( 

3877 self.key, 

3878 bytes(kdc_req), 

3879 ) 

3880 

3881 # Encrypt authenticator 

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

3883 

3884 # 5. Process FAST if required 

3885 if self.fast: 

3886 padata = [ 

3887 self._fast_wrap( 

3888 kdc_req=kdc_req, 

3889 padata=padata, 

3890 now_time=now_time, 

3891 pa_tgsreq_ap=apreq, 

3892 ) 

3893 ] 

3894 

3895 # 6. Add the final PADATA 

3896 padata.append(pa_tgs_req) 

3897 

3898 # 7. Build the request 

3899 tgsreq = Kerberos( 

3900 root=KRB_TGS_REQ( 

3901 padata=padata, 

3902 reqBody=kdc_req, 

3903 ) 

3904 ) 

3905 

3906 # Note the reply key 

3907 if self.subkey: 

3908 self.replykey = self.subkey 

3909 else: 

3910 self.replykey = self.key 

3911 

3912 return tgsreq 

3913 

3914 @ATMT.state(initial=1) 

3915 def BEGIN(self): 

3916 pass 

3917 

3918 @ATMT.condition(BEGIN) 

3919 def should_send_as_req(self): 

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

3921 raise self.SENT_AS_REQ() 

3922 

3923 @ATMT.condition(BEGIN) 

3924 def should_send_tgs_req(self): 

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

3926 raise self.SENT_TGS_REQ() 

3927 

3928 @ATMT.action(should_send_as_req) 

3929 def send_as_req(self): 

3930 self.send(self.as_req()) 

3931 

3932 @ATMT.action(should_send_tgs_req) 

3933 def send_tgs_req(self): 

3934 self.send(self.tgs_req()) 

3935 

3936 @ATMT.state() 

3937 def SENT_AS_REQ(self): 

3938 pass 

3939 

3940 @ATMT.state() 

3941 def SENT_TGS_REQ(self): 

3942 pass 

3943 

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

3945 """ 

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

3947 

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

3949 """ 

3950 salt = b"" 

3951 

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

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

3954 

3955 # 1. Process pa-data 

3956 if padatas is not None: 

3957 for padata in padatas: 

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

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

3960 elt = padata.padataValue.seq[0] 

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

3962 etype = elt.etype.val 

3963 if etype != EncryptionType.RC4_HMAC: 

3964 salt = elt.salt.val 

3965 

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

3967 # PKINIT handling 

3968 

3969 # The steps are as follows: 

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

3971 # is different depending on the used method. 

3972 # 2. Compute the replykey 

3973 

3974 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

3975 # Unpack KDCDHKeyInfo 

3976 keyinfo = self.pkinit_cms.verify( 

3977 padata.padataValue.rep.dhSignedData, 

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

3979 no_verify_cert=self.no_verify_cert, 

3980 ) 

3981 

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

3983 # the CMS successfully, end here. 

3984 if etype is None: 

3985 continue 

3986 

3987 # Extract crypto parameters 

3988 y = keyinfo.subjectPublicKey.y.val 

3989 

3990 # Import into cryptography 

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

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

3993 

3994 # Calculate DHSharedSecret 

3995 DHSharedSecret = self.pkinit_dh_key.exchange(pubkey) 

3996 

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

3998 self.replykey = octetstring2key( 

3999 etype, 

4000 DHSharedSecret, 

4001 ) 

4002 

4003 else: 

4004 raise ValueError 

4005 

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

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

4008 

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

4010 # Get cookie and store it 

4011 self.fxcookie = padata.padataValue 

4012 

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

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

4015 if isinstance(padata.padataValue, PA_FX_FAST_REPLY): 

4016 self.fast_rep = ( 

4017 padata.padataValue.armoredData.encFastRep.decrypt( 

4018 self.fast_armorkey, 

4019 ) 

4020 ) 

4021 

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

4023 # Get error and store it 

4024 self.fast_error = padata.padataValue 

4025 

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

4027 # Verify S4U checksum 

4028 key_usage_number = None 

4029 pasfux509 = padata.padataValue 

4030 # [MS-SFU] sect 2.2.2 

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

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

4033 key_usage_number = 27 

4034 pasfux509.checksum.verify( 

4035 self.key, 

4036 bytes(pasfux509.userId), 

4037 key_usage_number=key_usage_number, 

4038 ) 

4039 

4040 # 2. Update the current keys if necessary 

4041 

4042 # Compute client key if not already provided 

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

4044 self.key = Key.string_to_key( 

4045 etype, 

4046 self.password, 

4047 salt, 

4048 ) 

4049 

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

4051 if self.fast_rep and self.fast_rep.strengthenKey: 

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

4053 self.replykey = KRB_FX_CF2( 

4054 self.fast_rep.strengthenKey.toKey(), 

4055 self.replykey, 

4056 b"strengthenkey", 

4057 b"replykey", 

4058 ) 

4059 

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

4061 def receive_salt_mode(self, pkt): 

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

4063 # exit. 

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

4065 if Kerberos not in pkt: 

4066 raise self.FINAL() 

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

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

4069 raise self.FINAL() 

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

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

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

4073 elt = padata.padataValue.seq[0] 

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

4075 self.result = elt.salt.val 

4076 raise self.FINAL() 

4077 else: 

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

4079 raise self.FINAL() 

4080 

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

4082 def receive_krb_error_as_req(self, pkt): 

4083 # We check for Kerberos errors. 

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

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

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

4087 # Process PAs if available 

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

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

4090 

4091 # Special case for FAST errors 

4092 if self.fast_rep: 

4093 # This is actually a fast response error ! 

4094 frep, self.fast_rep = self.fast_rep, None 

4095 # Re-process PAs 

4096 self._process_padatas_and_key(frep.padata) 

4097 # Extract real Kerberos error from FAST message 

4098 ferr = Kerberos(root=self.fast_error) 

4099 self.fast_error = None 

4100 # Recurse 

4101 self.receive_krb_error_as_req(ferr) 

4102 return 

4103 

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

4105 if not self.key: 

4106 log_runtime.error( 

4107 "Got 'KDC_ERR_PREAUTH_REQUIRED', " 

4108 "but no possible key could be computed." 

4109 ) 

4110 raise self.FINAL() 

4111 self.should_followup = True 

4112 self.pre_auth = True 

4113 raise self.BEGIN() 

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

4115 self.should_followup = True 

4116 raise self.BEGIN() 

4117 else: 

4118 self._show_krb_error(pkt) 

4119 raise self.FINAL() 

4120 

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

4122 def receive_as_rep(self, pkt): 

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

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

4125 

4126 @ATMT.eof(SENT_AS_REQ) 

4127 def retry_after_eof_in_apreq(self): 

4128 if self.should_followup: 

4129 # Reconnect and Restart 

4130 self.should_followup = False 

4131 self.update_sock(self._connect()) 

4132 raise self.BEGIN() 

4133 else: 

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

4135 raise self.FINAL() 

4136 

4137 @ATMT.action(receive_as_rep) 

4138 def decrypt_as_rep(self, pkt): 

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

4140 self._process_padatas_and_key( 

4141 pkt.root.padata, 

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

4143 ) 

4144 

4145 if not self.pre_auth: 

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

4147 

4148 # Process FAST response 

4149 if self.fast_rep: 

4150 # Verify the ticket-checksum 

4151 self.fast_rep.finished.ticketChecksum.verify( 

4152 self.fast_armorkey, 

4153 bytes(pkt.root.ticket), 

4154 ) 

4155 # Process pa of FAST response 

4156 self._process_padatas_and_key( 

4157 self.fast_rep.padata, 

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

4159 ) 

4160 self.fast_rep = None 

4161 elif self.fast: 

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

4163 

4164 # Check for PKINIT 

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

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

4167 

4168 # Decrypt AS-REP response 

4169 enc = pkt.root.encPart 

4170 res = enc.decrypt(self.replykey) 

4171 self.result = self.RES_AS_MODE( 

4172 pkt.root, 

4173 res.key.toKey(), 

4174 res, 

4175 pkt.root.getUPN(), 

4176 self.pa_type, 

4177 ) 

4178 

4179 @ATMT.receive_condition(SENT_TGS_REQ) 

4180 def receive_krb_error_tgs_req(self, pkt): 

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

4182 # Process PAs if available 

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

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

4185 

4186 if self.fast_rep: 

4187 # This is actually a fast response error ! 

4188 frep, self.fast_rep = self.fast_rep, None 

4189 # Re-process PAs 

4190 self._process_padatas_and_key(frep.padata) 

4191 # Extract real Kerberos error from FAST message 

4192 ferr = Kerberos(root=self.fast_error) 

4193 self.fast_error = None 

4194 # Recurse 

4195 self.receive_krb_error_tgs_req(ferr) 

4196 return 

4197 

4198 self._show_krb_error(pkt) 

4199 raise self.FINAL() 

4200 

4201 @ATMT.receive_condition(SENT_TGS_REQ) 

4202 def receive_tgs_rep(self, pkt): 

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

4204 if ( 

4205 not self.renew 

4206 and not self.dmsa 

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

4208 ): 

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

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

4211 

4212 @ATMT.action(receive_tgs_rep) 

4213 def decrypt_tgs_rep(self, pkt): 

4214 self._process_padatas_and_key(pkt.root.padata) 

4215 

4216 # Process FAST response 

4217 if self.fast_rep: 

4218 # Verify the ticket-checksum 

4219 self.fast_rep.finished.ticketChecksum.verify( 

4220 self.fast_armorkey, 

4221 bytes(pkt.root.ticket), 

4222 ) 

4223 self.fast_rep = None 

4224 elif self.fast: 

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

4226 

4227 # Decrypt TGS-REP response 

4228 enc = pkt.root.encPart 

4229 if self.subkey: 

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

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

4232 # authenticator subkey is used." 

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

4234 else: 

4235 res = enc.decrypt(self.replykey) 

4236 

4237 # Store result 

4238 self.result = self.RES_TGS_MODE( 

4239 pkt.root, 

4240 res.key.toKey(), 

4241 res, 

4242 self.upn, 

4243 ) 

4244 

4245 @ATMT.state(final=1) 

4246 def FINAL(self): 

4247 pass 

4248 

4249 

4250def _parse_upn(upn): 

4251 """ 

4252 Extract the username and realm from full UPN 

4253 """ 

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

4255 if not m: 

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

4257 if "/" in upn: 

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

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

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

4261 raise ValueError(err) 

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

4263 user = m.group(1) 

4264 domain = m.group(3) 

4265 else: 

4266 user = m.group(3) 

4267 domain = m.group(1) 

4268 return user, domain 

4269 

4270 

4271def _parse_spn(spn): 

4272 """ 

4273 Extract ServiceName and realm from full SPN 

4274 """ 

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

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

4277 if not m: 

4278 try: 

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

4280 return _parse_upn(spn) 

4281 except ValueError: 

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

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

4284 

4285 

4286def _spn_are_equal(spn1, spn2): 

4287 """ 

4288 Check that two SPNs are equal. 

4289 """ 

4290 spn1, _ = _parse_spn(spn1) 

4291 spn2, _ = _parse_spn(spn2) 

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

4293 

4294 

4295def krb_as_req( 

4296 upn: Optional[str] = None, 

4297 spn: Optional[str] = None, 

4298 ip: Optional[str] = None, 

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

4300 password: Optional[str] = None, 

4301 realm: Optional[str] = None, 

4302 host: str = "WIN10", 

4303 p12: Optional[str] = None, 

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

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

4306 **kwargs, 

4307): 

4308 r""" 

4309 Kerberos AS-Req 

4310 

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

4312 or "user@DOMAIN" 

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

4314 Defaults to "krbtgt/<realm>" 

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

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

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

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

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

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

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

4322 'password' is the password of the p12. 

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

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

4325 

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

4327 

4328 Example:: 

4329 

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

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

4332 

4333 Equivalent:: 

4334 

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

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

4337 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

4339 

4340 Example using PKINIT with a p12 ("password" is the password of the p12):: 

4341 

4342 >>> krb_as_req(p12="./store.p12", realm="DOMAIN.LOCAL", password="password") 

4343 """ 

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

4345 if password is None: 

4346 try: 

4347 from prompt_toolkit import prompt 

4348 

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

4350 except ImportError: 

4351 password = input("Enter password: ") 

4352 cli = KerberosClient( 

4353 mode=KerberosClient.MODE.AS_REQ, 

4354 realm=realm, 

4355 ip=ip, 

4356 spn=spn, 

4357 host=host, 

4358 upn=upn, 

4359 password=password, 

4360 key=key, 

4361 p12=p12, 

4362 x509=x509, 

4363 x509key=x509key, 

4364 **kwargs, 

4365 ) 

4366 cli.run() 

4367 cli.stop() 

4368 return cli.result 

4369 

4370 

4371def krb_tgs_req( 

4372 upn, 

4373 spn, 

4374 sessionkey, 

4375 ticket, 

4376 ip=None, 

4377 renew=False, 

4378 realm=None, 

4379 additional_tickets=[], 

4380 u2u=False, 

4381 etypes=None, 

4382 for_user=None, 

4383 s4u2proxy=False, 

4384 **kwargs, 

4385): 

4386 r""" 

4387 Kerberos TGS-Req 

4388 

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

4390 or "user@DOMAIN" 

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

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

4393 :param ticket: the tgt ticket 

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

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

4396 :param renew: ask for renewal 

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

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

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

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

4401 :param etypes: array of EncryptionType values. 

4402 By default: AES128, AES256, RC4, DES_MD5 

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

4404 S4U2Self extension. 

4405 

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

4407 

4408 Example:: 

4409 

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

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

4412 

4413 Equivalent:: 

4414 

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

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

4417 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

4419 """ 

4420 cli = KerberosClient( 

4421 mode=KerberosClient.MODE.TGS_REQ, 

4422 realm=realm, 

4423 upn=upn, 

4424 ip=ip, 

4425 spn=spn, 

4426 key=sessionkey, 

4427 ticket=ticket, 

4428 renew=renew, 

4429 additional_tickets=additional_tickets, 

4430 u2u=u2u, 

4431 etypes=etypes, 

4432 for_user=for_user, 

4433 s4u2proxy=s4u2proxy, 

4434 **kwargs, 

4435 ) 

4436 cli.run() 

4437 cli.stop() 

4438 return cli.result 

4439 

4440 

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

4442 """ 

4443 Kerberos AS-Req then TGS-Req 

4444 """ 

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

4446 if not res: 

4447 return 

4448 

4449 return krb_tgs_req( 

4450 upn=res.upn, # UPN might get canonicalized 

4451 spn=spn, 

4452 sessionkey=res.sessionkey, 

4453 ticket=res.asrep.ticket, 

4454 ip=ip, 

4455 **kwargs, 

4456 ) 

4457 

4458 

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

4460 """ 

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

4462 """ 

4463 if realm is None: 

4464 _, realm = _parse_upn(upn) 

4465 cli = KerberosClient( 

4466 mode=KerberosClient.MODE.GET_SALT, 

4467 realm=realm, 

4468 ip=ip, 

4469 spn="krbtgt/" + realm, 

4470 upn=upn, 

4471 host=host, 

4472 **kwargs, 

4473 ) 

4474 cli.run() 

4475 cli.stop() 

4476 return cli.result 

4477 

4478 

4479def kpasswd( 

4480 upn, 

4481 targetupn=None, 

4482 ip=None, 

4483 password=None, 

4484 newpassword=None, 

4485 key=None, 

4486 ticket=None, 

4487 realm=None, 

4488 ssp=None, 

4489 setpassword=None, 

4490 timeout=3, 

4491 port=464, 

4492 debug=0, 

4493 **kwargs, 

4494): 

4495 """ 

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

4497 

4498 :param upn: the UPN to use for authentication 

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

4500 same as upn. 

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

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

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

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

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

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

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

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

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

4510 """ 

4511 from scapy.layers.ldap import dclocator 

4512 

4513 if not realm: 

4514 _, realm = _parse_upn(upn) 

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

4516 if ip is None: 

4517 ip = dclocator( 

4518 realm, 

4519 timeout=timeout, 

4520 # Use connect mode instead of ldap for compatibility 

4521 # with MIT kerberos servers 

4522 mode="connect", 

4523 port=port, 

4524 debug=debug, 

4525 ).ip 

4526 if ssp is None and ticket is not None: 

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

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

4529 if tktspn == "krbtgt": 

4530 log_runtime.info( 

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

4532 ) 

4533 setpassword = True 

4534 resp = krb_tgs_req( 

4535 upn=upn, 

4536 spn=spn, 

4537 ticket=ticket, 

4538 sessionkey=key, 

4539 ip=ip, 

4540 debug=debug, 

4541 ) 

4542 if resp is None: 

4543 return 

4544 ticket = resp.tgsrep.ticket 

4545 key = resp.sessionkey 

4546 if setpassword is None: 

4547 setpassword = bool(targetupn) 

4548 elif setpassword and targetupn is None: 

4549 targetupn = upn 

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

4551 # Get a ticket for kadmin/changepw 

4552 if ssp is None: 

4553 if ticket is None: 

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

4555 resp = krb_as_req( 

4556 upn=upn, 

4557 spn=spn, 

4558 key=key, 

4559 ip=ip, 

4560 password=password, 

4561 debug=debug, 

4562 ) 

4563 if resp is None: 

4564 return 

4565 ticket = resp.asrep.ticket 

4566 key = resp.sessionkey 

4567 ssp = KerberosSSP( 

4568 UPN=upn, 

4569 SPN=spn, 

4570 ST=ticket, 

4571 KEY=key, 

4572 DC_IP=ip, 

4573 debug=debug, 

4574 **kwargs, 

4575 ) 

4576 Context, tok, status = ssp.GSS_Init_sec_context( 

4577 None, 

4578 req_flags=0, # No GSS_C_MUTUAL_FLAG 

4579 ) 

4580 if status != GSS_S_CONTINUE_NEEDED: 

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

4582 if tok: 

4583 tok.show() 

4584 return 

4585 apreq = tok.innerToken.root 

4586 # Connect 

4587 sock = socket.socket() 

4588 sock.settimeout(timeout) 

4589 sock.connect((ip, port)) 

4590 sock = StreamSocket(sock, KpasswdTCPHeader) 

4591 # Do KPASSWD request 

4592 if newpassword is None: 

4593 try: 

4594 from prompt_toolkit import prompt 

4595 

4596 newpassword = prompt("Enter NEW password: ", is_password=True) 

4597 except ImportError: 

4598 newpassword = input("Enter NEW password: ") 

4599 krbpriv = KRB_PRIV(encPart=EncryptedData()) 

4600 krbpriv.encPart.encrypt( 

4601 Context.KrbSessionKey, 

4602 EncKrbPrivPart( 

4603 sAddress=HostAddress( 

4604 addrType=ASN1_INTEGER(2), # IPv4 

4605 address=ASN1_STRING(b"\xc0\xa8\x00e"), 

4606 ), 

4607 userData=ASN1_STRING( 

4608 bytes( 

4609 ChangePasswdData( 

4610 newpasswd=newpassword, 

4611 targname=PrincipalName.fromUPN(targetupn), 

4612 targrealm=realm, 

4613 ) 

4614 ) 

4615 if setpassword 

4616 else newpassword 

4617 ), 

4618 timestamp=None, 

4619 usec=None, 

4620 seqNumber=Context.SendSeqNum, 

4621 ), 

4622 ) 

4623 resp = sock.sr1( 

4624 KpasswdTCPHeader() 

4625 / KPASSWD_REQ( 

4626 pvno=0xFF80 if setpassword else 1, 

4627 apreq=apreq, 

4628 krbpriv=krbpriv, 

4629 ), 

4630 timeout=timeout, 

4631 verbose=0, 

4632 ) 

4633 # Verify KPASSWD response 

4634 if not resp: 

4635 raise TimeoutError("KPASSWD_REQ timed out !") 

4636 if KPASSWD_REP not in resp: 

4637 resp.show() 

4638 raise ValueError("Invalid response to KPASSWD_REQ !") 

4639 Context, tok, status = ssp.GSS_Init_sec_context( 

4640 Context, 

4641 input_token=resp.aprep, 

4642 ) 

4643 if status != GSS_S_COMPLETE: 

4644 warning("SSP failed on subsequent GSS_Init_sec_context !") 

4645 if tok: 

4646 tok.show() 

4647 return 

4648 # Parse answer KRB_PRIV 

4649 krbanswer = resp.krbpriv.encPart.decrypt(Context.KrbSessionKey) 

4650 userRep = KPasswdRepData(krbanswer.userData.val) 

4651 if userRep.resultCode != 0: 

4652 warning(userRep.sprintf("KPASSWD failed !")) 

4653 userRep.show() 

4654 return 

4655 print(userRep.sprintf("%resultCode%")) 

4656 

4657 

4658# SSP 

4659 

4660 

4661class KerberosSSP(SSP): 

4662 """ 

4663 The KerberosSSP 

4664 

4665 Client settings: 

4666 

4667 :param ST: the service ticket to use for access. 

4668 If not provided, will be retrieved 

4669 :param SPN: the SPN of the service to use. If not provided, will use the 

4670 target_name provided in the GSS_Init_sec_context 

4671 :param UPN: The client UPN 

4672 :param DC_IP: (optional) is ST+KEY are not provided, will need to contact 

4673 the KDC at this IP. If not provided, will perform dc locator. 

4674 :param TGT: (optional) pass a TGT to use to get the ST. 

4675 :param KEY: the session key associated with the ST if it is provided, 

4676 OR the session key associated with the TGT 

4677 OR the kerberos key associated with the UPN 

4678 :param PASSWORD: (optional) if a UPN is provided and not a KEY, this is the 

4679 password of the UPN. 

4680 :param U2U: (optional) use U2U when requesting the ST. 

4681 

4682 Server settings: 

4683 

4684 :param SPN: the SPN of the service to use. 

4685 :param KEY: the kerberos key to use to decrypt the AP-req 

4686 :param UPN: (optional) the UPN, if used in U2U mode. 

4687 :param TGT: (optional) pass a TGT to use for U2U. 

4688 :param DC_IP: (optional) if TGT is not provided, request one on the KDC at 

4689 this IP using using the KEY when using U2U. 

4690 """ 

4691 

4692 auth_type = 0x10 

4693 

4694 class STATE(SSP.STATE): 

4695 INIT = 1 

4696 CLI_SENT_TGTREQ = 2 

4697 CLI_SENT_APREQ = 3 

4698 CLI_RCVD_APREP = 4 

4699 SRV_SENT_APREP = 5 

4700 FAILED = -1 

4701 

4702 class CONTEXT(SSP.CONTEXT): 

4703 __slots__ = [ 

4704 "SessionKey", 

4705 "ServerHostname", 

4706 "U2U", 

4707 "KrbSessionKey", # raw Key object 

4708 "ST", # the service ticket 

4709 "STSessionKey", # raw ST Key object (for DCE_STYLE) 

4710 "SeqNum", # for AP 

4711 "SendSeqNum", # for MIC 

4712 "RecvSeqNum", # for MIC 

4713 "IsAcceptor", 

4714 "SendSealKeyUsage", 

4715 "SendSignKeyUsage", 

4716 "RecvSealKeyUsage", 

4717 "RecvSignKeyUsage", 

4718 # server-only 

4719 "UPN", 

4720 "PAC", 

4721 ] 

4722 

4723 def __init__(self, IsAcceptor, req_flags=None): 

4724 self.state = KerberosSSP.STATE.INIT 

4725 self.SessionKey = None 

4726 self.ServerHostname = None 

4727 self.U2U = False 

4728 self.SendSeqNum = 0 

4729 self.RecvSeqNum = 0 

4730 self.KrbSessionKey = None 

4731 self.ST = None 

4732 self.STSessionKey = None 

4733 self.IsAcceptor = IsAcceptor 

4734 self.UPN = None 

4735 self.PAC = None 

4736 # [RFC 4121] sect 2 

4737 if IsAcceptor: 

4738 self.SendSealKeyUsage = 22 

4739 self.SendSignKeyUsage = 23 

4740 self.RecvSealKeyUsage = 24 

4741 self.RecvSignKeyUsage = 25 

4742 else: 

4743 self.SendSealKeyUsage = 24 

4744 self.SendSignKeyUsage = 25 

4745 self.RecvSealKeyUsage = 22 

4746 self.RecvSignKeyUsage = 23 

4747 super(KerberosSSP.CONTEXT, self).__init__(req_flags=req_flags) 

4748 

4749 def clifailure(self): 

4750 self.__init__(self.IsAcceptor, req_flags=self.flags) 

4751 

4752 def __repr__(self): 

4753 if self.U2U: 

4754 return "KerberosSSP-U2U" 

4755 return "KerberosSSP" 

4756 

4757 def __init__( 

4758 self, 

4759 ST=None, 

4760 UPN=None, 

4761 PASSWORD=None, 

4762 U2U=False, 

4763 KEY=None, 

4764 SPN=None, 

4765 TGT=None, 

4766 DC_IP=None, 

4767 SKEY_TYPE=None, 

4768 debug=0, 

4769 **kwargs, 

4770 ): 

4771 import scapy.libs.rfc3961 # Trigger error if any # noqa: F401 

4772 

4773 self.ST = ST 

4774 self.UPN = UPN 

4775 self.KEY = KEY 

4776 self.SPN = SPN 

4777 self.TGT = TGT 

4778 self.TGTSessionKey = None 

4779 self.PASSWORD = PASSWORD 

4780 self.U2U = U2U 

4781 self.DC_IP = DC_IP 

4782 self.debug = debug 

4783 if SKEY_TYPE is None: 

4784 SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96 

4785 self.SKEY_TYPE = SKEY_TYPE 

4786 super(KerberosSSP, self).__init__(**kwargs) 

4787 

4788 def GSS_Inquire_names_for_mech(self): 

4789 mechs = [ 

4790 "1.2.840.48018.1.2.2", # MS KRB5 - Microsoft Kerberos 5 

4791 "1.2.840.113554.1.2.2", # Kerberos 5 

4792 ] 

4793 if self.U2U: 

4794 mechs.append("1.2.840.113554.1.2.2.3") # Kerberos 5 - User to User 

4795 return mechs 

4796 

4797 def GSS_GetMICEx(self, Context, msgs, qop_req=0): 

4798 """ 

4799 [MS-KILE] sect 3.4.5.6 

4800 

4801 - AES: RFC4121 sect 4.2.6.1 

4802 """ 

4803 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4804 # Concatenate the ToSign 

4805 ToSign = b"".join(x.data for x in msgs if x.sign) 

4806 sig = KRB_InnerToken( 

4807 TOK_ID=b"\x04\x04", 

4808 root=KRB_GSS_MIC( 

4809 Flags="AcceptorSubkey" 

4810 + ("+SentByAcceptor" if Context.IsAcceptor else ""), 

4811 SND_SEQ=Context.SendSeqNum, 

4812 ), 

4813 ) 

4814 ToSign += bytes(sig)[:16] 

4815 sig.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

4816 keyusage=Context.SendSignKeyUsage, 

4817 text=ToSign, 

4818 ) 

4819 else: 

4820 raise NotImplementedError 

4821 Context.SendSeqNum += 1 

4822 return sig 

4823 

4824 def GSS_VerifyMICEx(self, Context, msgs, signature): 

4825 """ 

4826 [MS-KILE] sect 3.4.5.7 

4827 

4828 - AES: RFC4121 sect 4.2.6.1 

4829 """ 

4830 Context.RecvSeqNum = signature.root.SND_SEQ 

4831 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4832 # Concatenate the ToSign 

4833 ToSign = b"".join(x.data for x in msgs if x.sign) 

4834 ToSign += bytes(signature)[:16] 

4835 sig = Context.KrbSessionKey.make_checksum( 

4836 keyusage=Context.RecvSignKeyUsage, 

4837 text=ToSign, 

4838 ) 

4839 else: 

4840 raise NotImplementedError 

4841 if sig != signature.root.SGN_CKSUM: 

4842 raise ValueError("ERROR: Checksums don't match") 

4843 

4844 def GSS_WrapEx(self, Context, msgs, qop_req: GSS_QOP_REQ_FLAGS = 0): 

4845 """ 

4846 [MS-KILE] sect 3.4.5.4 

4847 

4848 - AES: RFC4121 sect 4.2.6.2 and [MS-KILE] sect 3.4.5.4.1 

4849 - HMAC-RC4: RFC4757 sect 7.3 and [MS-KILE] sect 3.4.5.4.1 

4850 """ 

4851 # Is confidentiality in use? 

4852 confidentiality = (Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG) and any( 

4853 x.conf_req_flag for x in msgs 

4854 ) 

4855 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4856 # Build token 

4857 tok = KRB_InnerToken( 

4858 TOK_ID=b"\x05\x04", 

4859 root=KRB_GSS_Wrap( 

4860 Flags="AcceptorSubkey" 

4861 + ("+SentByAcceptor" if Context.IsAcceptor else "") 

4862 + ("+Sealed" if confidentiality else ""), 

4863 SND_SEQ=Context.SendSeqNum, 

4864 RRC=0, 

4865 ), 

4866 ) 

4867 Context.SendSeqNum += 1 

4868 # Real separation starts now: RFC4121 sect 4.2.4 

4869 if confidentiality: 

4870 # Confidentiality is requested (see RFC4121 sect 4.3) 

4871 # {"header" | encrypt(plaintext-data | filler | "header")} 

4872 # 0. Roll confounder 

4873 Confounder = os.urandom(Context.KrbSessionKey.ep.blocksize) 

4874 # 1. Concatenate the data to be encrypted 

4875 Data = b"".join(x.data for x in msgs if x.conf_req_flag) 

4876 DataLen = len(Data) 

4877 # 2. Add filler 

4878 if qop_req & GSS_QOP_REQ_FLAGS.GSS_S_NO_SECBUFFER_PADDING: 

4879 # Special case for compatibility with Windows API. See 

4880 # GSS_QOP_REQ_FLAGS. 

4881 tok.root.EC = 0 

4882 else: 

4883 # [MS-KILE] sect 3.4.5.4.1 - "For AES-SHA1 ciphers, the EC must not 

4884 # be zero" 

4885 tok.root.EC = ( 

4886 (-DataLen) % Context.KrbSessionKey.ep.blocksize 

4887 ) or 16 

4888 Filler = b"\x00" * tok.root.EC 

4889 Data += Filler 

4890 # 3. Add first 16 octets of the Wrap token "header" 

4891 PlainHeader = bytes(tok)[:16] 

4892 Data += PlainHeader 

4893 # 4. Build 'ToSign', exclusively used for checksum 

4894 ToSign = Confounder 

4895 ToSign += b"".join(x.data for x in msgs if x.sign) 

4896 ToSign += Filler 

4897 ToSign += PlainHeader 

4898 # 5. Finalize token for signing 

4899 # "The RRC field is [...] 28 if encryption is requested." 

4900 tok.root.RRC = 28 

4901 # 6. encrypt() is the encryption operation (which provides for 

4902 # integrity protection) 

4903 Data = Context.KrbSessionKey.encrypt( 

4904 keyusage=Context.SendSealKeyUsage, 

4905 plaintext=Data, 

4906 confounder=Confounder, 

4907 signtext=ToSign, 

4908 ) 

4909 # 7. Rotate 

4910 Data = strrot(Data, tok.root.RRC + tok.root.EC) 

4911 # 8. Split (token and encrypted messages) 

4912 toklen = len(Data) - DataLen 

4913 tok.root.Data = Data[:toklen] 

4914 offset = toklen 

4915 for msg in msgs: 

4916 msglen = len(msg.data) 

4917 if msg.conf_req_flag: 

4918 msg.data = Data[offset : offset + msglen] 

4919 offset += msglen 

4920 return msgs, tok 

4921 else: 

4922 # No confidentiality is requested 

4923 # {"header" | plaintext-data | get_mic(plaintext-data | "header")} 

4924 # 0. Concatenate the data 

4925 Data = b"".join(x.data for x in msgs if x.sign) 

4926 DataLen = len(Data) 

4927 # 1. Add first 16 octets of the Wrap token "header" 

4928 ToSign = Data 

4929 ToSign += bytes(tok)[:16] 

4930 # 2. get_mic() is the checksum operation for the required 

4931 # checksum mechanism 

4932 Mic = Context.KrbSessionKey.make_checksum( 

4933 keyusage=Context.SendSealKeyUsage, 

4934 text=ToSign, 

4935 ) 

4936 # In Wrap tokens without confidentiality, the EC field SHALL be used 

4937 # to encode the number of octets in the trailing checksum 

4938 tok.root.EC = 12 # len(tok.root.Data) == 12 for AES 

4939 # "The RRC field ([RFC4121] section 4.2.5) is 12 if no encryption 

4940 # is requested" 

4941 tok.root.RRC = 12 

4942 # 3. Concat and pack 

4943 for msg in msgs: 

4944 if msg.sign: 

4945 msg.data = b"" 

4946 Data = Data + Mic 

4947 # 4. Rotate 

4948 tok.root.Data = strrot(Data, tok.root.RRC) 

4949 return msgs, tok 

4950 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

4951 # Build token 

4952 seq = struct.pack(">I", Context.SendSeqNum) 

4953 tok = KRB_InnerToken( 

4954 TOK_ID=b"\x02\x01", 

4955 root=KRB_GSS_Wrap_RFC1964( 

4956 SGN_ALG="HMAC", 

4957 SEAL_ALG="RC4" if confidentiality else "none", 

4958 SND_SEQ=seq 

4959 + ( 

4960 # See errata 

4961 b"\xff\xff\xff\xff" 

4962 if Context.IsAcceptor 

4963 else b"\x00\x00\x00\x00" 

4964 ), 

4965 ), 

4966 ) 

4967 Context.SendSeqNum += 1 

4968 # 0. Concatenate data 

4969 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

4970 ToEncrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

4971 Kss = Context.KrbSessionKey.key 

4972 # 1. Roll confounder 

4973 Confounder = os.urandom(8) 

4974 # 2. Compute the 'Kseq' key 

4975 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

4976 if Context.KrbSessionKey.etype == 24: # EXP 

4977 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4978 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

4979 else: 

4980 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

4981 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

4982 # 3. Build SGN_CKSUM 

4983 tok.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

4984 keyusage=13, # See errata 

4985 text=bytes(tok)[:8] + Confounder + ToSign, 

4986 )[:8] 

4987 # 4. Populate token + encrypt 

4988 if confidentiality: 

4989 # 'encrypt' is requested 

4990 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

4991 tok.root.CONFOUNDER = rc4.update(Confounder) 

4992 Data = rc4.update(ToEncrypt) 

4993 # Split encrypted data 

4994 offset = 0 

4995 for msg in msgs: 

4996 msglen = len(msg.data) 

4997 if msg.conf_req_flag: 

4998 msg.data = Data[offset : offset + msglen] 

4999 offset += msglen 

5000 else: 

5001 # 'encrypt' is not requested 

5002 tok.root.CONFOUNDER = Confounder 

5003 # 5. Compute the 'Kseq' key 

5004 if Context.KrbSessionKey.etype == 24: # EXP 

5005 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5006 Kseq = Kseq[:7] + b"\xab" * 9 

5007 else: 

5008 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

5009 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

5010 # 6. Encrypt 'SND_SEQ' 

5011 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

5012 tok.root.SND_SEQ = rc4.update(tok.root.SND_SEQ) 

5013 # 7. Include 'InitialContextToken pseudo ASN.1 header' 

5014 tok = KRB_GSSAPI_Token( 

5015 MechType="1.2.840.113554.1.2.2", # Kerberos 5 

5016 innerToken=tok, 

5017 ) 

5018 return msgs, tok 

5019 else: 

5020 raise NotImplementedError 

5021 

5022 def GSS_UnwrapEx(self, Context, msgs, signature): 

5023 """ 

5024 [MS-KILE] sect 3.4.5.5 

5025 

5026 - AES: RFC4121 sect 4.2.6.2 

5027 - HMAC-RC4: RFC4757 sect 7.3 

5028 """ 

5029 if Context.KrbSessionKey.etype in [17, 18]: # AES 

5030 confidentiality = signature.root.Flags.Sealed 

5031 # Real separation starts now: RFC4121 sect 4.2.4 

5032 if confidentiality: 

5033 # 0. Concatenate the data 

5034 Data = signature.root.Data 

5035 Data += b"".join(x.data for x in msgs if x.conf_req_flag) 

5036 # 1. Un-Rotate 

5037 Data = strrot(Data, signature.root.RRC + signature.root.EC, right=False) 

5038 

5039 # 2. Function to build 'ToSign', exclusively used for checksum 

5040 def MakeToSign(Confounder, DecText): 

5041 offset = 0 

5042 # 2.a Confounder 

5043 ToSign = Confounder 

5044 # 2.b Messages 

5045 for msg in msgs: 

5046 msglen = len(msg.data) 

5047 if msg.conf_req_flag: 

5048 ToSign += DecText[offset : offset + msglen] 

5049 offset += msglen 

5050 elif msg.sign: 

5051 ToSign += msg.data 

5052 # 2.c Filler & Padding 

5053 ToSign += DecText[offset:] 

5054 return ToSign 

5055 

5056 # 3. Decrypt 

5057 Data = Context.KrbSessionKey.decrypt( 

5058 keyusage=Context.RecvSealKeyUsage, 

5059 ciphertext=Data, 

5060 presignfunc=MakeToSign, 

5061 ) 

5062 # 4. Split 

5063 Data, f16header = ( 

5064 Data[:-16], 

5065 Data[-16:], 

5066 ) 

5067 # 5. Check header 

5068 hdr = signature.copy() 

5069 hdr.root.RRC = 0 

5070 if f16header != bytes(hdr)[:16]: 

5071 raise ValueError("ERROR: Headers don't match") 

5072 # 6. Split (and ignore filler) 

5073 offset = 0 

5074 for msg in msgs: 

5075 msglen = len(msg.data) 

5076 if msg.conf_req_flag: 

5077 msg.data = Data[offset : offset + msglen] 

5078 offset += msglen 

5079 # Case without msgs 

5080 if len(msgs) == 1 and not msgs[0].data: 

5081 msgs[0].data = Data 

5082 return msgs 

5083 else: 

5084 # No confidentiality is requested 

5085 # 0. Concatenate the data 

5086 Data = signature.root.Data 

5087 Data += b"".join(x.data for x in msgs if x.sign) 

5088 # 1. Un-Rotate 

5089 Data = strrot(Data, signature.root.RRC, right=False) 

5090 # 2. Split 

5091 Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :] 

5092 # "Both the EC field and the RRC field in 

5093 # the token header SHALL be filled with zeroes for the purpose of 

5094 # calculating the checksum." 

5095 ToSign = Data 

5096 hdr = signature.copy() 

5097 hdr.root.RRC = 0 

5098 hdr.root.EC = 0 

5099 # Concatenate the data 

5100 ToSign += bytes(hdr)[:16] 

5101 # 3. Calculate the signature 

5102 sig = Context.KrbSessionKey.make_checksum( 

5103 keyusage=Context.RecvSealKeyUsage, 

5104 text=ToSign, 

5105 ) 

5106 # 4. Compare 

5107 if sig != Mic: 

5108 raise ValueError("ERROR: Checksums don't match") 

5109 # Case without msgs 

5110 if len(msgs) == 1 and not msgs[0].data: 

5111 msgs[0].data = Data 

5112 return msgs 

5113 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

5114 # Drop wrapping 

5115 tok = signature.innerToken 

5116 

5117 # Detect confidentiality 

5118 confidentiality = tok.root.SEAL_ALG != 0xFFFF 

5119 

5120 # 0. Concatenate data 

5121 ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

5122 Kss = Context.KrbSessionKey.key 

5123 # 1. Compute the 'Kseq' key 

5124 if Context.KrbSessionKey.etype == 24: # EXP 

5125 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5126 Kseq = Kseq[:7] + b"\xab" * 9 

5127 else: 

5128 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

5129 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

5130 # 2. Decrypt 'SND_SEQ' 

5131 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

5132 seq = rc4.update(tok.root.SND_SEQ)[:4] 

5133 # 3. Compute the 'Kcrypt' key 

5134 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

5135 if Context.KrbSessionKey.etype == 24: # EXP 

5136 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5137 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

5138 else: 

5139 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

5140 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

5141 # 4. Decrypt 

5142 if confidentiality: 

5143 # 'encrypt' was requested 

5144 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

5145 Confounder = rc4.update(tok.root.CONFOUNDER) 

5146 Data = rc4.update(ToDecrypt) 

5147 # Split encrypted data 

5148 offset = 0 

5149 for msg in msgs: 

5150 msglen = len(msg.data) 

5151 if msg.conf_req_flag: 

5152 msg.data = Data[offset : offset + msglen] 

5153 offset += msglen 

5154 else: 

5155 # 'encrypt' was not requested 

5156 Confounder = tok.root.CONFOUNDER 

5157 # 5. Verify SGN_CKSUM 

5158 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

5159 Context.KrbSessionKey.verify_checksum( 

5160 keyusage=13, # See errata 

5161 text=bytes(tok)[:8] + Confounder + ToSign, 

5162 cksum=tok.root.SGN_CKSUM, 

5163 ) 

5164 return msgs 

5165 else: 

5166 raise NotImplementedError 

5167 

5168 def GSS_Init_sec_context( 

5169 self, 

5170 Context: CONTEXT, 

5171 input_token=None, 

5172 target_name: Optional[str] = None, 

5173 req_flags: Optional[GSS_C_FLAGS] = None, 

5174 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5175 ): 

5176 if Context is None: 

5177 # New context 

5178 Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags) 

5179 

5180 if Context.state == self.STATE.INIT and self.U2U: 

5181 # U2U - Get TGT 

5182 Context.state = self.STATE.CLI_SENT_TGTREQ 

5183 return ( 

5184 Context, 

5185 KRB_GSSAPI_Token( 

5186 MechType="1.2.840.113554.1.2.2.3", # U2U 

5187 innerToken=KRB_InnerToken( 

5188 TOK_ID=b"\x04\x00", 

5189 root=KRB_TGT_REQ(), 

5190 ), 

5191 ), 

5192 GSS_S_CONTINUE_NEEDED, 

5193 ) 

5194 

5195 if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]: 

5196 if not self.UPN: 

5197 raise ValueError("Missing UPN attribute") 

5198 

5199 # Do we have a ST? 

5200 if self.ST is None: 

5201 # Client sends an AP-req 

5202 if not self.SPN and not target_name: 

5203 raise ValueError("Missing SPN/target_name attribute") 

5204 additional_tickets = [] 

5205 

5206 if self.U2U: 

5207 try: 

5208 # GSSAPI / Kerberos 

5209 tgt_rep = input_token.root.innerToken.root 

5210 except AttributeError: 

5211 try: 

5212 # Kerberos 

5213 tgt_rep = input_token.innerToken.root 

5214 except AttributeError: 

5215 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5216 if not isinstance(tgt_rep, KRB_TGT_REP): 

5217 tgt_rep.show() 

5218 raise ValueError("KerberosSSP: Unexpected input_token !") 

5219 additional_tickets = [tgt_rep.ticket] 

5220 

5221 if self.TGT is None: 

5222 # Get TGT. We were passed a kerberos key 

5223 res = krb_as_req( 

5224 upn=self.UPN, 

5225 ip=self.DC_IP, 

5226 key=self.KEY, 

5227 password=self.PASSWORD, 

5228 debug=self.debug, 

5229 verbose=bool(self.debug), 

5230 ) 

5231 if res is None: 

5232 # Failed to retrieve the ticket 

5233 return Context, None, GSS_S_FAILURE 

5234 

5235 # Update UPN (could have been canonicalized) 

5236 self.UPN = res.upn 

5237 

5238 # Store TGT, 

5239 self.TGT = res.asrep.ticket 

5240 self.TGTSessionKey = res.sessionkey 

5241 elif self.TGTSessionKey is None: 

5242 # We have a TGT and were passed its key 

5243 self.TGTSessionKey = self.KEY 

5244 

5245 # Get ST 

5246 if not self.TGTSessionKey: 

5247 raise ValueError("Cannot use TGT without the KEY") 

5248 

5249 res = krb_tgs_req( 

5250 upn=self.UPN, 

5251 spn=self.SPN or target_name, 

5252 ip=self.DC_IP, 

5253 sessionkey=self.TGTSessionKey, 

5254 ticket=self.TGT, 

5255 additional_tickets=additional_tickets, 

5256 u2u=self.U2U, 

5257 debug=self.debug, 

5258 verbose=bool(self.debug), 

5259 ) 

5260 if not res: 

5261 # Failed to retrieve the ticket 

5262 return Context, None, GSS_S_FAILURE 

5263 

5264 # Store the service ticket and associated key 

5265 Context.ST, Context.STSessionKey = res.tgsrep.ticket, res.sessionkey 

5266 elif not self.KEY: 

5267 raise ValueError("Must provide KEY with ST") 

5268 else: 

5269 # We were passed a ST and its key 

5270 Context.ST = self.ST 

5271 Context.STSessionKey = self.KEY 

5272 

5273 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5274 raise ValueError( 

5275 "Cannot use GSS_C_DELEG_FLAG when passed a service ticket !" 

5276 ) 

5277 

5278 # Save ServerHostname 

5279 if len(Context.ST.sname.nameString) == 2: 

5280 Context.ServerHostname = Context.ST.sname.nameString[1].val.decode() 

5281 

5282 # Build the KRB-AP 

5283 apOptions = ASN1_BIT_STRING("000") 

5284 if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG: 

5285 apOptions.set(2, "1") # mutual-required 

5286 if self.U2U: 

5287 apOptions.set(1, "1") # use-session-key 

5288 Context.U2U = True 

5289 ap_req = KRB_AP_REQ( 

5290 apOptions=apOptions, 

5291 ticket=Context.ST, 

5292 authenticator=EncryptedData(), 

5293 ) 

5294 

5295 # Get the current time 

5296 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5297 # Pick a random session key 

5298 Context.KrbSessionKey = Key.new_random_key( 

5299 self.SKEY_TYPE, 

5300 ) 

5301 

5302 # We use a random SendSeqNum 

5303 Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix() 

5304 

5305 # Get the realm of the client 

5306 _, crealm = _parse_upn(self.UPN) 

5307 

5308 # Build the RFC4121 authenticator checksum 

5309 authenticator_checksum = KRB_AuthenticatorChecksum( 

5310 # RFC 4121 sect 4.1.1.2 

5311 # "The Bnd field contains the MD5 hash of channel bindings" 

5312 Bnd=( 

5313 chan_bindings.digestMD5() 

5314 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5315 else (b"\x00" * 16) 

5316 ), 

5317 Flags=int(Context.flags), 

5318 ) 

5319 

5320 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5321 # Delegate TGT 

5322 raise NotImplementedError("GSS_C_DELEG_FLAG is not implemented !") 

5323 # authenticator_checksum.Deleg = KRB_CRED( 

5324 # tickets=[self.TGT], 

5325 # encPart=EncryptedData() 

5326 # ) 

5327 # authenticator_checksum.encPart.encrypt( 

5328 # Context.STSessionKey, 

5329 # EncKrbCredPart( 

5330 # ticketInfo=KrbCredInfo( 

5331 # key=EncryptionKey.fromKey(self.TGTSessionKey), 

5332 # prealm=ASN1_GENERAL_STRING(crealm), 

5333 # pname=PrincipalName.fromUPN(self.UPN), 

5334 # # TODO: rework API to pass starttime... here. 

5335 # sreralm=self.TGT.realm, 

5336 # sname=self.TGT.sname, 

5337 # ) 

5338 # ) 

5339 # ) 

5340 

5341 # Build and encrypt the full KRB_Authenticator 

5342 ap_req.authenticator.encrypt( 

5343 Context.STSessionKey, 

5344 KRB_Authenticator( 

5345 crealm=crealm, 

5346 cname=PrincipalName.fromUPN(self.UPN), 

5347 cksum=Checksum( 

5348 cksumtype="KRB-AUTHENTICATOR", checksum=authenticator_checksum 

5349 ), 

5350 ctime=ASN1_GENERALIZED_TIME(now_time), 

5351 cusec=ASN1_INTEGER(0), 

5352 subkey=EncryptionKey.fromKey(Context.KrbSessionKey), 

5353 seqNumber=Context.SendSeqNum, 

5354 encAuthorizationData=AuthorizationData( 

5355 seq=[ 

5356 AuthorizationDataItem( 

5357 adType="AD-IF-RELEVANT", 

5358 adData=AuthorizationData( 

5359 seq=[ 

5360 AuthorizationDataItem( 

5361 adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

5362 adData=KERB_AD_RESTRICTION_ENTRY( 

5363 restriction=LSAP_TOKEN_INFO_INTEGRITY( 

5364 MachineID=bytes(RandBin(32)), 

5365 PermanentMachineID=bytes( 

5366 RandBin(32) 

5367 ), 

5368 ) 

5369 ), 

5370 ), 

5371 # This isn't documented, but sent on Windows :/ 

5372 AuthorizationDataItem( 

5373 adType="KERB-LOCAL", 

5374 adData=b"\x00" * 16, 

5375 ), 

5376 ] 

5377 + ( 

5378 # Channel bindings 

5379 [ 

5380 AuthorizationDataItem( 

5381 adType="AD-AUTH-DATA-AP-OPTIONS", 

5382 adData=KERB_AUTH_DATA_AP_OPTIONS( 

5383 apOptions="KERB_AP_OPTIONS_CBT" 

5384 ), 

5385 ) 

5386 ] 

5387 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5388 else [] 

5389 ) 

5390 ), 

5391 ) 

5392 ] 

5393 ), 

5394 ), 

5395 ) 

5396 Context.state = self.STATE.CLI_SENT_APREQ 

5397 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5398 # Raw kerberos DCE-STYLE 

5399 return Context, ap_req, GSS_S_CONTINUE_NEEDED 

5400 else: 

5401 # Kerberos wrapper 

5402 return ( 

5403 Context, 

5404 KRB_GSSAPI_Token( 

5405 innerToken=KRB_InnerToken( 

5406 root=ap_req, 

5407 ) 

5408 ), 

5409 GSS_S_CONTINUE_NEEDED, 

5410 ) 

5411 

5412 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5413 if isinstance(input_token, KRB_AP_REP): 

5414 # Raw AP_REP was passed 

5415 ap_rep = input_token 

5416 else: 

5417 try: 

5418 # GSSAPI / Kerberos 

5419 ap_rep = input_token.root.innerToken.root 

5420 except AttributeError: 

5421 try: 

5422 # Kerberos 

5423 ap_rep = input_token.innerToken.root 

5424 except AttributeError: 

5425 try: 

5426 # Raw kerberos DCE-STYLE 

5427 ap_rep = input_token.root 

5428 except AttributeError: 

5429 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5430 if not isinstance(ap_rep, KRB_AP_REP): 

5431 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5432 

5433 # Retrieve SessionKey 

5434 repPart = ap_rep.encPart.decrypt(Context.STSessionKey) 

5435 if repPart.subkey is not None: 

5436 Context.SessionKey = repPart.subkey.keyvalue.val 

5437 Context.KrbSessionKey = repPart.subkey.toKey() 

5438 

5439 # OK ! 

5440 Context.state = self.STATE.CLI_RCVD_APREP 

5441 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5442 # [MS-KILE] sect 3.4.5.1 

5443 # The client MUST generate an additional AP exchange reply message 

5444 # exactly as the server would as the final message to send to the 

5445 # server. 

5446 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5447 cli_ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5448 cli_ap_rep.encPart.encrypt( 

5449 Context.STSessionKey, 

5450 EncAPRepPart( 

5451 ctime=ASN1_GENERALIZED_TIME(now_time), 

5452 seqNumber=repPart.seqNumber, 

5453 subkey=None, 

5454 ), 

5455 ) 

5456 return Context, cli_ap_rep, GSS_S_COMPLETE 

5457 return Context, None, GSS_S_COMPLETE 

5458 elif ( 

5459 Context.state == self.STATE.CLI_RCVD_APREP 

5460 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5461 ): 

5462 # DCE_STYLE with SPNEGOSSP 

5463 return Context, None, GSS_S_COMPLETE 

5464 else: 

5465 raise ValueError("KerberosSSP: Unknown state") 

5466 

5467 def GSS_Accept_sec_context( 

5468 self, 

5469 Context: CONTEXT, 

5470 input_token=None, 

5471 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5472 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5473 ): 

5474 if Context is None: 

5475 # New context 

5476 Context = self.CONTEXT(IsAcceptor=True, req_flags=req_flags) 

5477 

5478 import scapy.layers.msrpce.mspac # noqa: F401 

5479 

5480 if Context.state == self.STATE.INIT: 

5481 if self.UPN and self.SPN: 

5482 raise ValueError("Cannot use SPN and UPN at the same time !") 

5483 if self.SPN and self.TGT: 

5484 raise ValueError("Cannot use TGT with SPN.") 

5485 if self.UPN and not self.TGT: 

5486 # UPN is provided: use U2U 

5487 res = krb_as_req( 

5488 self.UPN, 

5489 self.DC_IP, 

5490 key=self.KEY, 

5491 password=self.PASSWORD, 

5492 ) 

5493 self.TGT, self.TGTSessionKey = res.asrep.ticket, res.sessionkey 

5494 

5495 # Server receives AP-req, sends AP-rep 

5496 if isinstance(input_token, KRB_AP_REQ): 

5497 # Raw AP_REQ was passed 

5498 ap_req = input_token 

5499 else: 

5500 try: 

5501 # GSSAPI/Kerberos 

5502 ap_req = input_token.root.innerToken.root 

5503 except AttributeError: 

5504 try: 

5505 # Kerberos 

5506 ap_req = input_token.innerToken.root 

5507 except AttributeError: 

5508 try: 

5509 # Raw kerberos 

5510 ap_req = input_token.root 

5511 except AttributeError: 

5512 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5513 

5514 if isinstance(ap_req, KRB_TGT_REQ): 

5515 # Special U2U case 

5516 Context.U2U = True 

5517 return ( 

5518 None, 

5519 KRB_GSSAPI_Token( 

5520 MechType="1.2.840.113554.1.2.2.3", # U2U 

5521 innerToken=KRB_InnerToken( 

5522 TOK_ID=b"\x04\x01", 

5523 root=KRB_TGT_REP( 

5524 ticket=self.TGT, 

5525 ), 

5526 ), 

5527 ), 

5528 GSS_S_CONTINUE_NEEDED, 

5529 ) 

5530 elif not isinstance(ap_req, KRB_AP_REQ): 

5531 ap_req.show() 

5532 raise ValueError("Unexpected type in KerberosSSP") 

5533 if not self.KEY: 

5534 raise ValueError("Missing KEY attribute") 

5535 

5536 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5537 

5538 # If using a UPN, require U2U 

5539 if self.UPN and ap_req.apOptions.val[1] != "1": # use-session-key 

5540 # Required but not provided. Return an error 

5541 Context.U2U = True 

5542 err = KRB_GSSAPI_Token( 

5543 innerToken=KRB_InnerToken( 

5544 TOK_ID=b"\x03\x00", 

5545 root=KRB_ERROR( 

5546 errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED", 

5547 stime=ASN1_GENERALIZED_TIME(now_time), 

5548 realm=ap_req.ticket.realm, 

5549 sname=ap_req.ticket.sname, 

5550 eData=KRB_TGT_REP( 

5551 ticket=self.TGT, 

5552 ), 

5553 ), 

5554 ) 

5555 ) 

5556 return Context, err, GSS_S_CONTINUE_NEEDED 

5557 

5558 # Validate the 'serverName' of the ticket. 

5559 sname = ap_req.ticket.getSPN() 

5560 our_sname = self.SPN or self.UPN 

5561 if not _spn_are_equal(our_sname, sname): 

5562 warning("KerberosSSP: bad server name: %s != %s" % (sname, our_sname)) 

5563 err = KRB_GSSAPI_Token( 

5564 innerToken=KRB_InnerToken( 

5565 TOK_ID=b"\x03\x00", 

5566 root=KRB_ERROR( 

5567 errorCode="KRB_AP_ERR_BADMATCH", 

5568 stime=ASN1_GENERALIZED_TIME(now_time), 

5569 realm=ap_req.ticket.realm, 

5570 sname=ap_req.ticket.sname, 

5571 eData=None, 

5572 ), 

5573 ) 

5574 ) 

5575 return Context, err, GSS_S_BAD_MECH 

5576 

5577 # Decrypt the ticket 

5578 try: 

5579 tkt = ap_req.ticket.encPart.decrypt(self.KEY) 

5580 except ValueError as ex: 

5581 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5582 err = KRB_GSSAPI_Token( 

5583 innerToken=KRB_InnerToken( 

5584 TOK_ID=b"\x03\x00", 

5585 root=KRB_ERROR( 

5586 errorCode="KRB_AP_ERR_MODIFIED", 

5587 stime=ASN1_GENERALIZED_TIME(now_time), 

5588 realm=ap_req.ticket.realm, 

5589 sname=ap_req.ticket.sname, 

5590 eData=None, 

5591 ), 

5592 ) 

5593 ) 

5594 return Context, err, GSS_S_DEFECTIVE_CREDENTIAL 

5595 

5596 # Store information about the user in the Context 

5597 if tkt.authorizationData and tkt.authorizationData.seq: 

5598 # Get AD-IF-RELEVANT 

5599 adIfRelevant = tkt.authorizationData.getAuthData(0x1) 

5600 if adIfRelevant: 

5601 # Get AD-WIN2K-PAC 

5602 Context.PAC = adIfRelevant.getAuthData(0x80) 

5603 

5604 # Get AP-REQ session key 

5605 Context.STSessionKey = tkt.key.toKey() 

5606 authenticator = ap_req.authenticator.decrypt(Context.STSessionKey) 

5607 

5608 # Compute an application session key ([MS-KILE] sect 3.1.1.2) 

5609 subkey = None 

5610 if ap_req.apOptions.val[2] == "1": # mutual-required 

5611 appkey = Key.new_random_key( 

5612 self.SKEY_TYPE, 

5613 ) 

5614 Context.KrbSessionKey = appkey 

5615 Context.SessionKey = appkey.key 

5616 subkey = EncryptionKey.fromKey(appkey) 

5617 else: 

5618 Context.KrbSessionKey = self.KEY 

5619 Context.SessionKey = self.KEY.key 

5620 

5621 # Eventually process the "checksum" 

5622 if authenticator.cksum and authenticator.cksum.cksumtype == 0x8003: 

5623 # KRB-Authenticator 

5624 authcksum = authenticator.cksum.checksum 

5625 Context.flags = authcksum.Flags 

5626 # Check channel bindings 

5627 if ( 

5628 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5629 and chan_bindings.digestMD5() != authcksum.Bnd 

5630 and not ( 

5631 GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS in req_flags 

5632 and authcksum.Bnd == GSS_C_NO_CHANNEL_BINDINGS 

5633 ) 

5634 ): 

5635 # Channel binding checks failed. 

5636 return Context, None, GSS_S_BAD_BINDINGS 

5637 elif ( 

5638 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5639 and GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS not in req_flags 

5640 ): 

5641 # Uhoh, we required channel bindings 

5642 return Context, None, GSS_S_BAD_BINDINGS 

5643 

5644 # Build response (RFC4120 sect 3.2.4) 

5645 ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5646 ap_rep.encPart.encrypt( 

5647 Context.STSessionKey, 

5648 EncAPRepPart( 

5649 ctime=authenticator.ctime, 

5650 cusec=authenticator.cusec, 

5651 seqNumber=None, 

5652 subkey=subkey, 

5653 ), 

5654 ) 

5655 Context.state = self.STATE.SRV_SENT_APREP 

5656 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5657 # [MS-KILE] sect 3.4.5.1 

5658 return Context, ap_rep, GSS_S_CONTINUE_NEEDED 

5659 return Context, ap_rep, GSS_S_COMPLETE # success 

5660 elif ( 

5661 Context.state == self.STATE.SRV_SENT_APREP 

5662 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5663 ): 

5664 # [MS-KILE] sect 3.4.5.1 

5665 # The server MUST receive the additional AP exchange reply message and 

5666 # verify that the message is constructed correctly. 

5667 if not input_token: 

5668 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5669 # Server receives AP-req, sends AP-rep 

5670 if isinstance(input_token, KRB_AP_REP): 

5671 # Raw AP_REP was passed 

5672 ap_rep = input_token 

5673 else: 

5674 try: 

5675 # GSSAPI/Kerberos 

5676 ap_rep = input_token.root.innerToken.root 

5677 except AttributeError: 

5678 try: 

5679 # Raw Kerberos 

5680 ap_rep = input_token.root 

5681 except AttributeError: 

5682 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5683 # Decrypt the AP-REP 

5684 try: 

5685 ap_rep.encPart.decrypt(Context.STSessionKey) 

5686 except ValueError as ex: 

5687 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5688 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5689 return Context, None, GSS_S_COMPLETE # success 

5690 else: 

5691 raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state)) 

5692 

5693 def GSS_Passive( 

5694 self, 

5695 Context: CONTEXT, 

5696 input_token=None, 

5697 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5698 ): 

5699 if Context is None: 

5700 Context = self.CONTEXT(True) 

5701 Context.passive = True 

5702 

5703 if Context.state == self.STATE.INIT or ( 

5704 # In DCE/RPC, there's an extra AP-REP sent from the client. 

5705 Context.state == self.STATE.SRV_SENT_APREP 

5706 and req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5707 ): 

5708 Context, _, status = self.GSS_Accept_sec_context( 

5709 Context, 

5710 input_token=input_token, 

5711 req_flags=req_flags, 

5712 ) 

5713 if status in [GSS_S_CONTINUE_NEEDED, GSS_S_COMPLETE]: 

5714 Context.state = self.STATE.CLI_SENT_APREQ 

5715 else: 

5716 Context.state = self.STATE.FAILED 

5717 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5718 Context, _, status = self.GSS_Init_sec_context( 

5719 Context, 

5720 input_token=input_token, 

5721 req_flags=req_flags, 

5722 ) 

5723 if status == GSS_S_COMPLETE: 

5724 if req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5725 status = GSS_S_CONTINUE_NEEDED 

5726 Context.state = self.STATE.SRV_SENT_APREP 

5727 else: 

5728 Context.state == self.STATE.FAILED 

5729 else: 

5730 # Unknown state. Don't crash though. 

5731 status = GSS_S_FAILURE 

5732 

5733 return Context, status 

5734 

5735 def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False): 

5736 if Context.IsAcceptor is not IsAcceptor: 

5737 return 

5738 # Swap everything 

5739 Context.SendSealKeyUsage, Context.RecvSealKeyUsage = ( 

5740 Context.RecvSealKeyUsage, 

5741 Context.SendSealKeyUsage, 

5742 ) 

5743 Context.SendSignKeyUsage, Context.RecvSignKeyUsage = ( 

5744 Context.RecvSignKeyUsage, 

5745 Context.SendSignKeyUsage, 

5746 ) 

5747 Context.IsAcceptor = not Context.IsAcceptor 

5748 

5749 def LegsAmount(self, Context: CONTEXT): 

5750 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5751 return 4 

5752 else: 

5753 return 2 

5754 

5755 def MaximumSignatureLength(self, Context: CONTEXT): 

5756 if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG: 

5757 # TODO: support DES 

5758 if Context.KrbSessionKey.etype in [17, 18]: # AES 

5759 return 76 

5760 elif Context.KrbSessionKey.etype in [23, 24]: # RC4_HMAC 

5761 return 45 

5762 else: 

5763 raise NotImplementedError 

5764 else: 

5765 return 28