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

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

1760 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): 

273 """ 

274 Create a PrincipalName from a UPN string. 

275 """ 

276 user, _ = _parse_upn(upn) 

277 return PrincipalName( 

278 nameString=[ASN1_GENERAL_STRING(user)], 

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

280 ) 

281 

282 @staticmethod 

283 def fromSPN(spn: str): 

284 """ 

285 Create a PrincipalName from a SPN string. 

286 """ 

287 spn, _ = _parse_spn(spn) 

288 if spn.startswith("krbtgt"): 

289 return PrincipalName( 

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

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

292 ) 

293 elif "/" in spn: 

294 return PrincipalName( 

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

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

297 ) 

298 else: 

299 # In case of U2U 

300 return PrincipalName( 

301 nameString=[ASN1_GENERAL_STRING(spn)], 

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

303 ) 

304 

305 

306KerberosTime = ASN1F_GENERALIZED_TIME 

307Microseconds = ASN1F_INTEGER 

308 

309 

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

311 

312_KRB_E_TYPES = { 

313 1: "DES-CBC-CRC", 

314 2: "DES-CBC-MD4", 

315 3: "DES-CBC-MD5", 

316 5: "DES3-CBC-MD5", 

317 7: "DES3-CBC-SHA1", 

318 9: "DSAWITHSHA1-CMSOID", 

319 10: "MD5WITHRSAENCRYPTION-CMSOID", 

320 11: "SHA1WITHRSAENCRYPTION-CMSOID", 

321 12: "RC2CBC-ENVOID", 

322 13: "RSAENCRYPTION-ENVOID", 

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

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

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

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

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

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

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

330 23: "RC4-HMAC", 

331 24: "RC4-HMAC-EXP", 

332 25: "CAMELLIA128-CTS-CMAC", 

333 26: "CAMELLIA256-CTS-CMAC", 

334} 

335 

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

337 

338_KRB_S_TYPES = { 

339 1: "CRC32", 

340 2: "RSA-MD4", 

341 3: "RSA-MD4-DES", 

342 4: "DES-MAC", 

343 5: "DES-MAC-K", 

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

345 7: "RSA-MD5", 

346 8: "RSA-MD5-DES", 

347 9: "RSA-MD5-DES3", 

348 10: "SHA1", 

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

350 13: "HMAC-SHA1-DES3", 

351 14: "SHA1", 

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

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

354 17: "CMAC-CAMELLIA128", 

355 18: "CMAC-CAMELLIA256", 

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

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

358 # RFC 4121 

359 0x8003: "KRB-AUTHENTICATOR", 

360 # [MS-KILE] 

361 0xFFFFFF76: "MD5", 

362 -138: "MD5", 

363} 

364 

365 

366class EncryptedData(ASN1_Packet): 

367 ASN1_codec = ASN1_Codecs.BER 

368 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

372 ) 

373 

374 def get_usage(self): 

375 """ 

376 Get current key usage number and encrypted class 

377 """ 

378 # RFC 4120 sect 7.5.1 

379 if self.underlayer: 

380 if isinstance(self.underlayer, PADATA): 

381 patype = self.underlayer.padataType 

382 if patype == 2: 

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

384 return 1, PA_ENC_TS_ENC 

385 elif patype == 138: 

386 # RFC6113 PA-ENC-TS-ENC 

387 return 54, PA_ENC_TS_ENC 

388 elif isinstance(self.underlayer, KRB_Ticket): 

389 # AS-REP Ticket and TGS-REP Ticket 

390 return 2, EncTicketPart 

391 elif isinstance(self.underlayer, KRB_AS_REP): 

392 # AS-REP encrypted part 

393 return 3, EncASRepPart 

394 elif isinstance(self.underlayer, KRB_KDC_REQ_BODY): 

395 # KDC-REQ enc-authorization-data 

396 return 4, AuthorizationData 

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

398 self.underlayer.underlayer, PADATA 

399 ): 

400 # TGS-REQ PA-TGS-REQ Authenticator 

401 return 7, KRB_Authenticator 

402 elif isinstance(self.underlayer, KRB_TGS_REP): 

403 # TGS-REP encrypted part 

404 return 8, EncTGSRepPart 

405 elif isinstance(self.underlayer, KRB_AP_REQ): 

406 # AP-REQ Authenticator 

407 return 11, KRB_Authenticator 

408 elif isinstance(self.underlayer, KRB_AP_REP): 

409 # AP-REP encrypted part 

410 return 12, EncAPRepPart 

411 elif isinstance(self.underlayer, KRB_PRIV): 

412 # KRB-PRIV encrypted part 

413 return 13, EncKrbPrivPart 

414 elif isinstance(self.underlayer, KRB_CRED): 

415 # KRB-CRED encrypted part 

416 return 14, EncKrbCredPart 

417 elif isinstance(self.underlayer, KrbFastArmoredReq): 

418 # KEY_USAGE_FAST_ENC 

419 return 51, KrbFastReq 

420 elif isinstance(self.underlayer, KrbFastArmoredRep): 

421 # KEY_USAGE_FAST_REP 

422 return 52, KrbFastResponse 

423 raise ValueError( 

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

425 ) 

426 

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

428 """ 

429 Decrypt and return the data contained in cipher. 

430 

431 :param key: the key to use for decryption 

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

433 Guessed otherwise 

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

435 Guessed otherwise (or bytes) 

436 """ 

437 if key_usage_number is None: 

438 key_usage_number, cls = self.get_usage() 

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

440 if cls: 

441 try: 

442 return cls(d) 

443 except BER_Decoding_Error: 

444 if cls == EncASRepPart: 

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

446 # "Compatibility note: Some implementations unconditionally send an 

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

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

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

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

451 try: 

452 res = EncTGSRepPart(d) 

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

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

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

456 log_runtime.warning( 

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

458 ) 

459 return res 

460 except BER_Decoding_Error: 

461 pass 

462 raise 

463 return d 

464 

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

466 """ 

467 Encrypt text and set it into cipher. 

468 

469 :param key: the key to use for encryption 

470 :param text: the bytes value to encode 

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

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

473 Guessed otherwise 

474 """ 

475 if key_usage_number is None: 

476 key_usage_number = self.get_usage()[0] 

477 self.etype = key.etype 

478 self.cipher = ASN1_STRING( 

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

480 ) 

481 

482 

483class EncryptionKey(ASN1_Packet): 

484 ASN1_codec = ASN1_Codecs.BER 

485 ASN1_root = ASN1F_SEQUENCE( 

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

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

488 ) 

489 

490 def toKey(self): 

491 return Key( 

492 etype=self.keytype.val, 

493 key=self.keyvalue.val, 

494 ) 

495 

496 @classmethod 

497 def fromKey(self, key): 

498 return EncryptionKey( 

499 keytype=key.etype, 

500 keyvalue=key.key, 

501 ) 

502 

503 

504class _Checksum_Field(ASN1F_STRING_PacketField): 

505 def m2i(self, pkt, s): 

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

507 if not val[0].val: 

508 return val 

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

510 # Special case per RFC 4121 

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

512 return val 

513 

514 

515class Checksum(ASN1_Packet): 

516 ASN1_codec = ASN1_Codecs.BER 

517 ASN1_root = ASN1F_SEQUENCE( 

518 ASN1F_enum_INTEGER( 

519 "cksumtype", 

520 0, 

521 _KRB_S_TYPES, 

522 explicit_tag=0xA0, 

523 ), 

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

525 ) 

526 

527 def get_usage(self): 

528 """ 

529 Get current key usage number 

530 """ 

531 # RFC 4120 sect 7.5.1 

532 if self.underlayer: 

533 if isinstance(self.underlayer, KRB_Authenticator): 

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

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

536 return 6 

537 elif isinstance(self.underlayer, PA_FOR_USER): 

538 # [MS-SFU] sect 2.2.1 

539 return 17 

540 elif isinstance(self.underlayer, PA_S4U_X509_USER): 

541 # [MS-SFU] sect 2.2.2 

542 return 26 

543 elif isinstance(self.underlayer, AD_KDCIssued): 

544 # AD-KDC-ISSUED checksum 

545 return 19 

546 elif isinstance(self.underlayer, KrbFastArmoredReq): 

547 # KEY_USAGE_FAST_REQ_CHKSUM 

548 return 50 

549 elif isinstance(self.underlayer, KrbFastFinished): 

550 # KEY_USAGE_FAST_FINISHED 

551 return 53 

552 raise ValueError( 

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

554 ) 

555 

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

557 """ 

558 Verify a signature of text using a key. 

559 

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

561 :param text: the bytes to verify 

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

563 Guessed otherwise 

564 """ 

565 if key_usage_number is None: 

566 key_usage_number = self.get_usage() 

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

568 

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

570 """ 

571 Make a signature. 

572 

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

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

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

576 Guessed otherwise 

577 """ 

578 if key_usage_number is None: 

579 key_usage_number = self.get_usage() 

580 self.cksumtype = cksumtype or key.cksumtype 

581 self.checksum = ASN1_STRING( 

582 key.make_checksum( 

583 keyusage=key_usage_number, 

584 text=text, 

585 cksumtype=self.cksumtype, 

586 ) 

587 ) 

588 

589 

590KerberosFlags = ASN1F_FLAGS 

591 

592_ADDR_TYPES = { 

593 # RFC4120 sect 7.5.3 

594 0x02: "IPv4", 

595 0x03: "Directional", 

596 0x05: "ChaosNet", 

597 0x06: "XNS", 

598 0x07: "ISO", 

599 0x0C: "DECNET Phase IV", 

600 0x10: "AppleTalk DDP", 

601 0x14: "NetBios", 

602 0x18: "IPv6", 

603} 

604 

605 

606class HostAddress(ASN1_Packet): 

607 ASN1_codec = ASN1_Codecs.BER 

608 ASN1_root = ASN1F_SEQUENCE( 

609 ASN1F_enum_INTEGER( 

610 "addrType", 

611 0, 

612 _ADDR_TYPES, 

613 explicit_tag=0xA0, 

614 ), 

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

616 ) 

617 

618 

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

620 name, [], HostAddress, **kwargs 

621) 

622 

623 

624_AUTHORIZATIONDATA_VALUES = { 

625 # Filled below 

626} 

627 

628 

629class _AuthorizationData_value_Field(ASN1F_STRING_PacketField): 

630 def m2i(self, pkt, s): 

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

632 if not val[0].val: 

633 return val 

634 if pkt.adType.val in _AUTHORIZATIONDATA_VALUES: 

635 return ( 

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

637 val[1], 

638 ) 

639 return val 

640 

641 

642_AD_TYPES = { 

643 # RFC4120 sect 7.5.4 

644 1: "AD-IF-RELEVANT", 

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

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

647 4: "AD-KDC-ISSUED", 

648 5: "AD-AND-OR", 

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

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

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

652 64: "OSF-DCE", 

653 65: "SESAME", 

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

655 128: "AD-WIN2K-PAC", 

656 129: "AD-ETYPE-NEGOTIATION", 

657 # [MS-KILE] additions 

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

659 142: "KERB-LOCAL", 

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

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

662} 

663 

664 

665class AuthorizationDataItem(ASN1_Packet): 

666 ASN1_codec = ASN1_Codecs.BER 

667 ASN1_root = ASN1F_SEQUENCE( 

668 ASN1F_enum_INTEGER( 

669 "adType", 

670 0, 

671 _AD_TYPES, 

672 explicit_tag=0xA0, 

673 ), 

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

675 ) 

676 

677 

678class AuthorizationData(ASN1_Packet): 

679 ASN1_codec = ASN1_Codecs.BER 

680 ASN1_root = ASN1F_SEQUENCE_OF( 

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

682 ) 

683 

684 def getAuthData(self, adType): 

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

686 

687 

688AD_IF_RELEVANT = AuthorizationData 

689_AUTHORIZATIONDATA_VALUES[1] = AD_IF_RELEVANT 

690 

691 

692class AD_KDCIssued(ASN1_Packet): 

693 ASN1_codec = ASN1_Codecs.BER 

694 ASN1_root = ASN1F_SEQUENCE( 

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

696 ASN1F_optional( 

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

698 ), 

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

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

701 ) 

702 

703 

704_AUTHORIZATIONDATA_VALUES[4] = AD_KDCIssued 

705 

706 

707class AD_AND_OR(ASN1_Packet): 

708 ASN1_codec = ASN1_Codecs.BER 

709 ASN1_root = ASN1F_SEQUENCE( 

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

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

712 ) 

713 

714 

715_AUTHORIZATIONDATA_VALUES[5] = AD_AND_OR 

716 

717ADMANDATORYFORKDC = AuthorizationData 

718_AUTHORIZATIONDATA_VALUES[8] = ADMANDATORYFORKDC 

719 

720 

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

722_PADATA_TYPES = { 

723 1: "PA-TGS-REQ", 

724 2: "PA-ENC-TIMESTAMP", 

725 3: "PA-PW-SALT", 

726 11: "PA-ETYPE-INFO", 

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

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

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

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

731 19: "PA-ETYPE-INFO2", 

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

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

734 128: "PA-PAC-REQUEST", 

735 129: "PA-FOR-USER", 

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

737 131: "PA-FOR-CHECK_DUPS", 

738 132: "PA-AS-CHECKSUM", 

739 133: "PA-FX-COOKIE", 

740 134: "PA-AUTHENTICATION-SET", 

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

742 136: "PA-FX-FAST", 

743 137: "PA-FX-ERROR", 

744 138: "PA-ENCRYPTED-CHALLENGE", 

745 141: "PA-OTP-CHALLENGE", 

746 142: "PA-OTP-REQUEST", 

747 143: "PA-OTP-CONFIRM", 

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

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

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

751 147: "PA-PKINIT-KX", 

752 148: "PA-PKU2U-NAME", 

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

754 150: "PA-AS-FRESHNESS", 

755 151: "PA-SPAKE", 

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

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

758 165: "PA-SUPPORTED-ENCTYPES", 

759 166: "PA-EXTENDED-ERROR", 

760 167: "PA-PAC-OPTIONS", 

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

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

763} 

764 

765_PADATA_CLASSES = { 

766 # Filled elsewhere in this file 

767} 

768 

769 

770# RFC4120 

771 

772 

773class _PADATA_value_Field(ASN1F_STRING_PacketField): 

774 """ 

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

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

777 """ 

778 

779 def m2i(self, pkt, s): 

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

781 if pkt.padataType.val in _PADATA_CLASSES: 

782 cls = _PADATA_CLASSES[pkt.padataType.val] 

783 if isinstance(cls, tuple): 

784 parent = pkt.underlayer or pkt.parent 

785 is_reply = False 

786 if parent is not None: 

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

788 is_reply = True 

789 else: 

790 parent = parent.underlayer or parent.parent 

791 is_reply = isinstance(parent, KRB_ERROR) 

792 cls = cls[is_reply] 

793 if not val[0].val: 

794 return val 

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

796 return val 

797 

798 

799class PADATA(ASN1_Packet): 

800 ASN1_codec = ASN1_Codecs.BER 

801 ASN1_root = ASN1F_SEQUENCE( 

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

803 _PADATA_value_Field( 

804 "padataValue", 

805 "", 

806 explicit_tag=0xA2, 

807 ), 

808 ) 

809 

810 

811# RFC 4120 sect 5.2.7.2 

812 

813 

814class PA_ENC_TS_ENC(ASN1_Packet): 

815 ASN1_codec = ASN1_Codecs.BER 

816 ASN1_root = ASN1F_SEQUENCE( 

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

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

819 ) 

820 

821 

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

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

824 

825 

826# RFC 4120 sect 5.2.7.4 

827 

828 

829class ETYPE_INFO_ENTRY(ASN1_Packet): 

830 ASN1_codec = ASN1_Codecs.BER 

831 ASN1_root = ASN1F_SEQUENCE( 

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

833 ASN1F_optional( 

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

835 ), 

836 ) 

837 

838 

839class ETYPE_INFO(ASN1_Packet): 

840 ASN1_codec = ASN1_Codecs.BER 

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

842 

843 

844_PADATA_CLASSES[11] = ETYPE_INFO 

845 

846# RFC 4120 sect 5.2.7.5 

847 

848 

849class ETYPE_INFO_ENTRY2(ASN1_Packet): 

850 ASN1_codec = ASN1_Codecs.BER 

851 ASN1_root = ASN1F_SEQUENCE( 

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

853 ASN1F_optional( 

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

855 ), 

856 ASN1F_optional( 

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

858 ), 

859 ) 

860 

861 

862class ETYPE_INFO2(ASN1_Packet): 

863 ASN1_codec = ASN1_Codecs.BER 

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

865 

866 

867_PADATA_CLASSES[19] = ETYPE_INFO2 

868 

869 

870# RFC8636 - PKINIT Algorithm Agility 

871 

872 

873class TD_CMS_DIGEST_ALGORITHMS(ASN1_Packet): 

874 ASN1_codec = ASN1_Codecs.BER 

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

876 

877 

878_PADATA_CLASSES[111] = TD_CMS_DIGEST_ALGORITHMS 

879 

880 

881# PADATA Extended with RFC6113 

882 

883 

884class PA_AUTHENTICATION_SET_ELEM(ASN1_Packet): 

885 ASN1_codec = ASN1_Codecs.BER 

886 ASN1_root = ASN1F_SEQUENCE( 

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

888 ASN1F_optional( 

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

890 ), 

891 ASN1F_optional( 

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

893 ), 

894 ) 

895 

896 

897class PA_AUTHENTICATION_SET(ASN1_Packet): 

898 ASN1_codec = ASN1_Codecs.BER 

899 ASN1_root = ASN1F_SEQUENCE_OF( 

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

901 ) 

902 

903 

904_PADATA_CLASSES[134] = PA_AUTHENTICATION_SET 

905 

906 

907# [MS-KILE] sect 2.2.3 

908 

909 

910class PA_PAC_REQUEST(ASN1_Packet): 

911 ASN1_codec = ASN1_Codecs.BER 

912 ASN1_root = ASN1F_SEQUENCE( 

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

914 ) 

915 

916 

917_PADATA_CLASSES[128] = PA_PAC_REQUEST 

918 

919 

920# [MS-KILE] sect 2.2.5 

921 

922 

923class LSAP_TOKEN_INFO_INTEGRITY(Packet): 

924 fields_desc = [ 

925 FlagsField( 

926 "Flags", 

927 0, 

928 -32, 

929 { 

930 0x00000001: "UAC-Restricted", 

931 }, 

932 ), 

933 LEIntEnumField( 

934 "TokenIL", 

935 0x00002000, 

936 { 

937 0x00000000: "Untrusted", 

938 0x00001000: "Low", 

939 0x00002000: "Medium", 

940 0x00003000: "High", 

941 0x00004000: "System", 

942 0x00005000: "Protected process", 

943 }, 

944 ), 

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

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

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

948 ] 

949 

950 

951# [MS-KILE] sect 2.2.6 

952 

953 

954class _KerbAdRestrictionEntry_Field(ASN1F_STRING_PacketField): 

955 def m2i(self, pkt, s): 

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

957 if not val[0].val: 

958 return val 

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

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

961 return val 

962 

963 

964class KERB_AD_RESTRICTION_ENTRY(ASN1_Packet): 

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

966 ASN1_codec = ASN1_Codecs.BER 

967 ASN1_root = ASN1F_SEQUENCE( 

968 ASN1F_SEQUENCE( 

969 ASN1F_enum_INTEGER( 

970 "restrictionType", 

971 0, 

972 {0: "LSAP_TOKEN_INFO_INTEGRITY"}, 

973 explicit_tag=0xA0, 

974 ), 

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

976 ) 

977 ) 

978 

979 

980_AUTHORIZATIONDATA_VALUES[141] = KERB_AD_RESTRICTION_ENTRY 

981 

982 

983# [MS-KILE] sect 3.2.5.8 

984 

985 

986class KERB_AUTH_DATA_AP_OPTIONS(Packet): 

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

988 fields_desc = [ 

989 FlagsField( 

990 "apOptions", 

991 0x4000, 

992 -32, 

993 { 

994 0x4000: "KERB_AP_OPTIONS_CBT", 

995 0x8000: "KERB_AP_OPTIONS_UNVERIFIED_TARGET_NAME", 

996 }, 

997 ), 

998 ] 

999 

1000 

1001_AUTHORIZATIONDATA_VALUES[143] = KERB_AUTH_DATA_AP_OPTIONS 

1002 

1003 

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

1005 

1006 

1007class KERB_AUTH_DATA_CLIENT_TARGET(Packet): 

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

1009 fields_desc = [ 

1010 StrFieldUtf16("spn", ""), 

1011 ] 

1012 

1013 

1014_AUTHORIZATIONDATA_VALUES[144] = KERB_AUTH_DATA_CLIENT_TARGET 

1015 

1016 

1017# RFC6806 sect 6 

1018 

1019 

1020class KERB_AD_LOGIN_ALIAS(ASN1_Packet): 

1021 ASN1_codec = ASN1_Codecs.BER 

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

1023 

1024 

1025_AUTHORIZATIONDATA_VALUES[80] = KERB_AD_LOGIN_ALIAS 

1026 

1027 

1028# [MS-KILE] sect 2.2.8 

1029 

1030 

1031class PA_SUPPORTED_ENCTYPES(Packet): 

1032 fields_desc = [ 

1033 FlagsField( 

1034 "flags", 

1035 0, 

1036 -32, 

1037 [ 

1038 "DES-CBC-CRC", 

1039 "DES-CBC-MD5", 

1040 "RC4-HMAC", 

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

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

1043 ] 

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

1045 + [ 

1046 "FAST-supported", 

1047 "Compount-identity-supported", 

1048 "Claims-supported", 

1049 "Resource-SID-compression-disabled", 

1050 ], 

1051 ) 

1052 ] 

1053 

1054 

1055_PADATA_CLASSES[165] = PA_SUPPORTED_ENCTYPES 

1056 

1057# [MS-KILE] sect 2.2.10 

1058 

1059 

1060class PA_PAC_OPTIONS(ASN1_Packet): 

1061 ASN1_codec = ASN1_Codecs.BER 

1062 ASN1_root = ASN1F_SEQUENCE( 

1063 KerberosFlags( 

1064 "options", 

1065 "", 

1066 [ 

1067 "Claims", 

1068 "Branch-Aware", 

1069 "Forward-to-Full-DC", 

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

1071 ], 

1072 explicit_tag=0xA0, 

1073 ) 

1074 ) 

1075 

1076 

1077_PADATA_CLASSES[167] = PA_PAC_OPTIONS 

1078 

1079# [MS-KILE] sect 2.2.11 

1080 

1081 

1082class KERB_KEY_LIST_REQ(ASN1_Packet): 

1083 ASN1_codec = ASN1_Codecs.BER 

1084 ASN1_root = ASN1F_SEQUENCE_OF( 

1085 "keytypes", 

1086 [], 

1087 ASN1F_enum_INTEGER("", 0, _KRB_E_TYPES), 

1088 ) 

1089 

1090 

1091_PADATA_CLASSES[161] = KERB_KEY_LIST_REQ 

1092 

1093# [MS-KILE] sect 2.2.12 

1094 

1095 

1096class KERB_KEY_LIST_REP(ASN1_Packet): 

1097 ASN1_codec = ASN1_Codecs.BER 

1098 ASN1_root = ASN1F_SEQUENCE_OF( 

1099 "keys", 

1100 [], 

1101 ASN1F_PACKET("", None, EncryptionKey), 

1102 ) 

1103 

1104 

1105_PADATA_CLASSES[162] = KERB_KEY_LIST_REP 

1106 

1107# [MS-KILE] sect 2.2.13 

1108 

1109 

1110class KERB_SUPERSEDED_BY_USER(ASN1_Packet): 

1111 ASN1_codec = ASN1_Codecs.BER 

1112 ASN1_root = ASN1F_SEQUENCE( 

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

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

1115 ) 

1116 

1117 

1118_PADATA_CLASSES[170] = KERB_SUPERSEDED_BY_USER 

1119 

1120 

1121# [MS-KILE] sect 2.2.14 

1122 

1123 

1124class KERB_DMSA_KEY_PACKAGE(ASN1_Packet): 

1125 ASN1_codec = ASN1_Codecs.BER 

1126 ASN1_root = ASN1F_SEQUENCE( 

1127 ASN1F_SEQUENCE_OF( 

1128 "currentKeys", 

1129 [], 

1130 ASN1F_PACKET("", None, EncryptionKey), 

1131 explicit_tag=0xA0, 

1132 ), 

1133 ASN1F_optional( 

1134 ASN1F_SEQUENCE_OF( 

1135 "previousKeys", 

1136 [], 

1137 ASN1F_PACKET("", None, EncryptionKey), 

1138 explicit_tag=0xA1, 

1139 ), 

1140 ), 

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

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

1143 ) 

1144 

1145 

1146_PADATA_CLASSES[171] = KERB_DMSA_KEY_PACKAGE 

1147 

1148 

1149# RFC6113 sect 5.4.1 

1150 

1151 

1152class _KrbFastArmor_value_Field(ASN1F_STRING_PacketField): 

1153 def m2i(self, pkt, s): 

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

1155 if not val[0].val: 

1156 return val 

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

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

1159 return val 

1160 

1161 

1162class KrbFastArmor(ASN1_Packet): 

1163 ASN1_codec = ASN1_Codecs.BER 

1164 ASN1_root = ASN1F_SEQUENCE( 

1165 ASN1F_enum_INTEGER( 

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

1167 ), 

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

1169 ) 

1170 

1171 

1172# RFC6113 sect 5.4.2 

1173 

1174 

1175class KrbFastArmoredReq(ASN1_Packet): 

1176 ASN1_codec = ASN1_Codecs.BER 

1177 ASN1_root = ASN1F_SEQUENCE( 

1178 ASN1F_SEQUENCE( 

1179 ASN1F_optional( 

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

1181 ), 

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

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

1184 ) 

1185 ) 

1186 

1187 

1188class PA_FX_FAST_REQUEST(ASN1_Packet): 

1189 ASN1_codec = ASN1_Codecs.BER 

1190 ASN1_root = ASN1F_CHOICE( 

1191 "armoredData", 

1192 ASN1_STRING(""), 

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

1194 ) 

1195 

1196 

1197# RFC6113 sect 5.4.3 

1198 

1199 

1200class KrbFastArmoredRep(ASN1_Packet): 

1201 ASN1_codec = ASN1_Codecs.BER 

1202 ASN1_root = ASN1F_SEQUENCE( 

1203 ASN1F_SEQUENCE( 

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

1205 ) 

1206 ) 

1207 

1208 

1209class PA_FX_FAST_REPLY(ASN1_Packet): 

1210 ASN1_codec = ASN1_Codecs.BER 

1211 ASN1_root = ASN1F_CHOICE( 

1212 "armoredData", 

1213 ASN1_STRING(""), 

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

1215 ) 

1216 

1217 

1218class KrbFastFinished(ASN1_Packet): 

1219 ASN1_codec = ASN1_Codecs.BER 

1220 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

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

1226 ) 

1227 

1228 

1229class KrbFastResponse(ASN1_Packet): 

1230 ASN1_codec = ASN1_Codecs.BER 

1231 ASN1_root = ASN1F_SEQUENCE( 

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

1233 ASN1F_optional( 

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

1235 ), 

1236 ASN1F_optional( 

1237 ASN1F_PACKET( 

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

1239 ) 

1240 ), 

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

1242 ) 

1243 

1244 

1245_PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY) 

1246 

1247 

1248# RFC 4556 - PKINIT 

1249 

1250 

1251# sect 3.2.1 

1252 

1253 

1254class ExternalPrincipalIdentifier(ASN1_Packet): 

1255 ASN1_codec = ASN1_Codecs.BER 

1256 ASN1_root = ASN1F_SEQUENCE( 

1257 ASN1F_optional( 

1258 ASN1F_STRING_ENCAPS( 

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

1260 ), 

1261 ), 

1262 ASN1F_optional( 

1263 ASN1F_STRING_ENCAPS( 

1264 "issuerAndSerialNumber", 

1265 None, 

1266 CMS_IssuerAndSerialNumber, 

1267 implicit_tag=0x81, 

1268 ), 

1269 ), 

1270 ASN1F_optional( 

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

1272 ), 

1273 ) 

1274 

1275 

1276class PA_PK_AS_REQ(ASN1_Packet): 

1277 ASN1_codec = ASN1_Codecs.BER 

1278 ASN1_root = ASN1F_SEQUENCE( 

1279 ASN1F_STRING_ENCAPS( 

1280 "signedAuthpack", 

1281 CMS_ContentInfo(), 

1282 CMS_ContentInfo, 

1283 implicit_tag=0x80, 

1284 ), 

1285 ASN1F_optional( 

1286 ASN1F_SEQUENCE_OF( 

1287 "trustedCertifiers", 

1288 None, 

1289 ExternalPrincipalIdentifier, 

1290 explicit_tag=0xA1, 

1291 ), 

1292 ), 

1293 ASN1F_optional( 

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

1295 ), 

1296 ) 

1297 

1298 

1299_PADATA_CLASSES[16] = PA_PK_AS_REQ 

1300 

1301 

1302# [MS-PKCA] sect 2.2.3 

1303 

1304 

1305class PAChecksum2(ASN1_Packet): 

1306 ASN1_codec = ASN1_Codecs.BER 

1307 ASN1_root = ASN1F_SEQUENCE( 

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

1309 ASN1F_PACKET( 

1310 "algorithmIdentifier", 

1311 X509_AlgorithmIdentifier(), 

1312 X509_AlgorithmIdentifier, 

1313 explicit_tag=0xA1, 

1314 ), 

1315 ) 

1316 

1317 def verify(self, text): 

1318 """ 

1319 Verify a checksum of text. 

1320 

1321 :param text: the bytes to verify 

1322 """ 

1323 # [MS-PKCA] 2.2.3 - PAChecksum2 

1324 

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

1326 oid = self.algorithmIdentifier.algorithm.val 

1327 if oid == "1.3.14.3.2.26": 

1328 hashcls = Hash_SHA 

1329 elif oid == "2.16.840.1.101.3.4.2.1": 

1330 hashcls = Hash_SHA256 

1331 elif oid == "2.16.840.1.101.3.4.2.2": 

1332 hashcls = Hash_SHA384 

1333 elif oid == "2.16.840.1.101.3.4.2.3": 

1334 hashcls = Hash_SHA512 

1335 else: 

1336 raise ValueError("Bad PAChecksum2 checksum !") 

1337 

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

1339 raise ValueError("Bad PAChecksum2 checksum !") 

1340 

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

1342 """ 

1343 Make a checksum. 

1344 

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

1346 """ 

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

1348 if h == "sha1": 

1349 hashcls = Hash_SHA 

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

1351 elif h == "sha256": 

1352 hashcls = Hash_SHA256 

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

1354 elif h == "sha384": 

1355 hashcls = Hash_SHA384 

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

1357 elif h == "sha512": 

1358 hashcls = Hash_SHA512 

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

1360 else: 

1361 raise ValueError("Bad PAChecksum2 checksum !") 

1362 

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

1364 

1365 

1366# still RFC 4556 sect 3.2.1 

1367 

1368 

1369class KRB_PKAuthenticator(ASN1_Packet): 

1370 ASN1_codec = ASN1_Codecs.BER 

1371 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

1375 ASN1F_optional( 

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

1377 ), 

1378 # RFC8070 extension 

1379 ASN1F_optional( 

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

1381 ), 

1382 # [MS-PKCA] sect 2.2.3 

1383 ASN1F_optional( 

1384 ASN1F_PACKET("paChecksum2", PAChecksum2(), PAChecksum2, explicit_tag=0xA5), 

1385 ), 

1386 ) 

1387 

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

1389 """ 

1390 Populate paChecksum and paChecksum2 

1391 """ 

1392 # paChecksum (always sha-1) 

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

1394 

1395 # paChecksum2 

1396 self.paChecksum2 = PAChecksum2() 

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

1398 

1399 def verify_checksum(self, text): 

1400 """ 

1401 Verify paChecksum and paChecksum2 

1402 """ 

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

1404 raise ValueError("Bad paChecksum checksum !") 

1405 

1406 self.paChecksum2.verify(text) 

1407 

1408 

1409# RFC8636 sect 6 

1410 

1411 

1412class KDFAlgorithmId(ASN1_Packet): 

1413 ASN1_codec = ASN1_Codecs.BER 

1414 ASN1_root = ASN1F_SEQUENCE( 

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

1416 ) 

1417 

1418 

1419# still RFC 4556 sect 3.2.1 

1420 

1421 

1422class KRB_AuthPack(ASN1_Packet): 

1423 ASN1_codec = ASN1_Codecs.BER 

1424 ASN1_root = ASN1F_SEQUENCE( 

1425 ASN1F_PACKET( 

1426 "pkAuthenticator", 

1427 KRB_PKAuthenticator(), 

1428 KRB_PKAuthenticator, 

1429 explicit_tag=0xA0, 

1430 ), 

1431 ASN1F_optional( 

1432 ASN1F_PACKET( 

1433 "clientPublicValue", 

1434 X509_SubjectPublicKeyInfo(), 

1435 X509_SubjectPublicKeyInfo, 

1436 explicit_tag=0xA1, 

1437 ), 

1438 ), 

1439 ASN1F_optional( 

1440 ASN1F_SEQUENCE_OF( 

1441 "supportedCMSTypes", 

1442 None, 

1443 X509_AlgorithmIdentifier, 

1444 explicit_tag=0xA2, 

1445 ), 

1446 ), 

1447 ASN1F_optional( 

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

1449 ), 

1450 # RFC8636 extension 

1451 ASN1F_optional( 

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

1453 ), 

1454 ) 

1455 

1456 

1457_CMS_ENCAPSULATED["1.3.6.1.5.2.3.1"] = KRB_AuthPack 

1458 

1459# sect 3.2.3 

1460 

1461 

1462class DHRepInfo(ASN1_Packet): 

1463 ASN1_codec = ASN1_Codecs.BER 

1464 ASN1_root = ASN1F_SEQUENCE( 

1465 ASN1F_STRING_ENCAPS( 

1466 "dhSignedData", 

1467 CMS_ContentInfo(), 

1468 CMS_ContentInfo, 

1469 implicit_tag=0x80, 

1470 ), 

1471 ASN1F_optional( 

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

1473 ), 

1474 # RFC8636 extension 

1475 ASN1F_optional( 

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

1477 ), 

1478 ) 

1479 

1480 

1481class EncKeyPack(ASN1_Packet): 

1482 ASN1_codec = ASN1_Codecs.BER 

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

1484 

1485 

1486class PA_PK_AS_REP(ASN1_Packet): 

1487 ASN1_codec = ASN1_Codecs.BER 

1488 ASN1_root = ASN1F_CHOICE( 

1489 "rep", 

1490 ASN1_STRING(""), 

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

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

1493 ) 

1494 

1495 

1496_PADATA_CLASSES[17] = PA_PK_AS_REP 

1497 

1498 

1499class KDCDHKeyInfo(ASN1_Packet): 

1500 ASN1_codec = ASN1_Codecs.BER 

1501 ASN1_root = ASN1F_SEQUENCE( 

1502 ASN1F_BIT_STRING_ENCAPS( 

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

1504 ), 

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

1506 ASN1F_optional( 

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

1508 ), 

1509 ) 

1510 

1511 

1512_CMS_ENCAPSULATED["1.3.6.1.5.2.3.2"] = KDCDHKeyInfo 

1513 

1514# [MS-SFU] 

1515 

1516 

1517# sect 2.2.1 

1518class PA_FOR_USER(ASN1_Packet): 

1519 ASN1_codec = ASN1_Codecs.BER 

1520 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

1525 ) 

1526 

1527 

1528_PADATA_CLASSES[129] = PA_FOR_USER 

1529 

1530 

1531# sect 2.2.2 

1532 

1533 

1534class S4UUserID(ASN1_Packet): 

1535 ASN1_codec = ASN1_Codecs.BER 

1536 ASN1_root = ASN1F_SEQUENCE( 

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

1538 ASN1F_optional( 

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

1540 ), 

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

1542 ASN1F_optional( 

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

1544 ), 

1545 ASN1F_optional( 

1546 ASN1F_FLAGS( 

1547 "options", 

1548 "", 

1549 [ 

1550 "reserved", 

1551 "KDC_CHECK_LOGON_HOUR_RESTRICTIONS", 

1552 "USE_REPLY_KEY_USAGE", 

1553 "NT_AUTH_POLICY_NOT_REQUIRED", 

1554 "UNCONDITIONAL_DELEGATION", 

1555 ], 

1556 explicit_tag=0xA4, 

1557 ) 

1558 ), 

1559 ) 

1560 

1561 

1562class PA_S4U_X509_USER(ASN1_Packet): 

1563 ASN1_codec = ASN1_Codecs.BER 

1564 ASN1_root = ASN1F_SEQUENCE( 

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

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

1567 ) 

1568 

1569 

1570_PADATA_CLASSES[130] = PA_S4U_X509_USER 

1571 

1572 

1573# Back to RFC4120 

1574 

1575# sect 5.10 

1576KRB_MSG_TYPES = { 

1577 1: "Ticket", 

1578 2: "Authenticator", 

1579 3: "EncTicketPart", 

1580 10: "AS-REQ", 

1581 11: "AS-REP", 

1582 12: "TGS-REQ", 

1583 13: "TGS-REP", 

1584 14: "AP-REQ", 

1585 15: "AP-REP", 

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

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

1588 20: "KRB-SAFE", 

1589 21: "KRB-PRIV", 

1590 22: "KRB-CRED", 

1591 25: "EncASRepPart", 

1592 26: "EncTGSRepPart", 

1593 27: "EncAPRepPart", 

1594 28: "EncKrbPrivPart", 

1595 29: "EnvKrbCredPart", 

1596 30: "KRB-ERROR", 

1597} 

1598 

1599# sect 5.3 

1600 

1601 

1602class KRB_Ticket(ASN1_Packet): 

1603 ASN1_codec = ASN1_Codecs.BER 

1604 ASN1_root = ASN1F_SEQUENCE( 

1605 ASN1F_SEQUENCE( 

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

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

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

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

1610 ), 

1611 implicit_tag=ASN1_Class_KRB.Ticket, 

1612 ) 

1613 

1614 def getSPN(self): 

1615 return "%s@%s" % ( 

1616 self.sname.toString(), 

1617 self.realm.val.decode(), 

1618 ) 

1619 

1620 

1621class TransitedEncoding(ASN1_Packet): 

1622 ASN1_codec = ASN1_Codecs.BER 

1623 ASN1_root = ASN1F_SEQUENCE( 

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

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

1626 ) 

1627 

1628 

1629_TICKET_FLAGS = [ 

1630 "reserved", 

1631 "forwardable", 

1632 "forwarded", 

1633 "proxiable", 

1634 "proxy", 

1635 "may-postdate", 

1636 "postdated", 

1637 "invalid", 

1638 "renewable", 

1639 "initial", 

1640 "pre-authent", 

1641 "hw-authent", 

1642 "transited-since-policy-checked", 

1643 "ok-as-delegate", 

1644 "unused", 

1645 "canonicalize", # RFC6806 

1646 "anonymous", # RFC6112 + RFC8129 

1647] 

1648 

1649 

1650class EncTicketPart(ASN1_Packet): 

1651 ASN1_codec = ASN1_Codecs.BER 

1652 ASN1_root = ASN1F_SEQUENCE( 

1653 ASN1F_SEQUENCE( 

1654 KerberosFlags( 

1655 "flags", 

1656 "", 

1657 _TICKET_FLAGS, 

1658 explicit_tag=0xA0, 

1659 ), 

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

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

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

1663 ASN1F_PACKET( 

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

1665 ), 

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

1667 ASN1F_optional( 

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

1669 ), 

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

1671 ASN1F_optional( 

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

1673 ), 

1674 ASN1F_optional( 

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

1676 ), 

1677 ASN1F_optional( 

1678 ASN1F_PACKET( 

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

1680 ), 

1681 ), 

1682 ), 

1683 implicit_tag=ASN1_Class_KRB.EncTicketPart, 

1684 ) 

1685 

1686 

1687# sect 5.4.1 

1688 

1689 

1690class KRB_KDC_REQ_BODY(ASN1_Packet): 

1691 ASN1_codec = ASN1_Codecs.BER 

1692 ASN1_root = ASN1F_SEQUENCE( 

1693 KerberosFlags( 

1694 "kdcOptions", 

1695 "", 

1696 [ 

1697 "reserved", 

1698 "forwardable", 

1699 "forwarded", 

1700 "proxiable", 

1701 "proxy", 

1702 "allow-postdate", 

1703 "postdated", 

1704 "unused7", 

1705 "renewable", 

1706 "unused9", 

1707 "unused10", 

1708 "opt-hardware-auth", 

1709 "unused12", 

1710 "unused13", 

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

1712 "canonicalize", # RFC6806 

1713 "request-anonymous", # RFC6112 + RFC8129 

1714 ] 

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

1716 + [ 

1717 "disable-transited-check", 

1718 "renewable-ok", 

1719 "enc-tkt-in-skey", 

1720 "unused29", 

1721 "renew", 

1722 "validate", 

1723 ], 

1724 explicit_tag=0xA0, 

1725 ), 

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

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

1728 ASN1F_optional( 

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

1730 ), 

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

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

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

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

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

1736 ASN1F_optional( 

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

1738 ), 

1739 ASN1F_optional( 

1740 ASN1F_PACKET( 

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

1742 ), 

1743 ), 

1744 ASN1F_optional( 

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

1746 ), 

1747 ) 

1748 

1749 

1750KRB_KDC_REQ = ASN1F_SEQUENCE( 

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

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

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

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

1755) 

1756 

1757 

1758class KrbFastReq(ASN1_Packet): 

1759 # RFC6113 sect 5.4.2 

1760 ASN1_codec = ASN1_Codecs.BER 

1761 ASN1_root = ASN1F_SEQUENCE( 

1762 KerberosFlags( 

1763 "fastOptions", 

1764 "", 

1765 [ 

1766 "RESERVED", 

1767 "hide-client-names", 

1768 ] 

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

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

1771 explicit_tag=0xA0, 

1772 ), 

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

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

1775 ) 

1776 

1777 

1778class KRB_AS_REQ(ASN1_Packet): 

1779 ASN1_codec = ASN1_Codecs.BER 

1780 ASN1_root = ASN1F_SEQUENCE( 

1781 KRB_KDC_REQ, 

1782 implicit_tag=ASN1_Class_KRB.AS_REQ, 

1783 ) 

1784 

1785 

1786class KRB_TGS_REQ(ASN1_Packet): 

1787 ASN1_codec = ASN1_Codecs.BER 

1788 ASN1_root = ASN1F_SEQUENCE( 

1789 KRB_KDC_REQ, 

1790 implicit_tag=ASN1_Class_KRB.TGS_REQ, 

1791 ) 

1792 msgType = ASN1_INTEGER(12) 

1793 

1794 

1795# sect 5.4.2 

1796 

1797KRB_KDC_REP = ASN1F_SEQUENCE( 

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

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

1800 ASN1F_optional( 

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

1802 ), 

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

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

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

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

1807) 

1808 

1809 

1810class KRB_AS_REP(ASN1_Packet): 

1811 ASN1_codec = ASN1_Codecs.BER 

1812 ASN1_root = ASN1F_SEQUENCE( 

1813 KRB_KDC_REP, 

1814 implicit_tag=ASN1_Class_KRB.AS_REP, 

1815 ) 

1816 

1817 def getUPN(self): 

1818 return "%s@%s" % ( 

1819 self.cname.toString(), 

1820 self.crealm.val.decode(), 

1821 ) 

1822 

1823 

1824class KRB_TGS_REP(ASN1_Packet): 

1825 ASN1_codec = ASN1_Codecs.BER 

1826 ASN1_root = ASN1F_SEQUENCE( 

1827 KRB_KDC_REP, 

1828 implicit_tag=ASN1_Class_KRB.TGS_REP, 

1829 ) 

1830 

1831 def getUPN(self): 

1832 return "%s@%s" % ( 

1833 self.cname.toString(), 

1834 self.crealm.val.decode(), 

1835 ) 

1836 

1837 

1838class LastReqItem(ASN1_Packet): 

1839 ASN1_codec = ASN1_Codecs.BER 

1840 ASN1_root = ASN1F_SEQUENCE( 

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

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

1843 ) 

1844 

1845 

1846EncKDCRepPart = ASN1F_SEQUENCE( 

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

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

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

1850 ASN1F_optional( 

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

1852 ), 

1853 KerberosFlags( 

1854 "flags", 

1855 "", 

1856 _TICKET_FLAGS, 

1857 explicit_tag=0xA4, 

1858 ), 

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

1860 ASN1F_optional( 

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

1862 ), 

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

1864 ASN1F_optional( 

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

1866 ), 

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

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

1869 ASN1F_optional( 

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

1871 ), 

1872 # RFC6806 sect 11 

1873 ASN1F_optional( 

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

1875 ), 

1876) 

1877 

1878 

1879class EncASRepPart(ASN1_Packet): 

1880 ASN1_codec = ASN1_Codecs.BER 

1881 ASN1_root = ASN1F_SEQUENCE( 

1882 EncKDCRepPart, 

1883 implicit_tag=ASN1_Class_KRB.EncASRepPart, 

1884 ) 

1885 

1886 

1887class EncTGSRepPart(ASN1_Packet): 

1888 ASN1_codec = ASN1_Codecs.BER 

1889 ASN1_root = ASN1F_SEQUENCE( 

1890 EncKDCRepPart, 

1891 implicit_tag=ASN1_Class_KRB.EncTGSRepPart, 

1892 ) 

1893 

1894 

1895# sect 5.5.1 

1896 

1897 

1898class KRB_AP_REQ(ASN1_Packet): 

1899 ASN1_codec = ASN1_Codecs.BER 

1900 ASN1_root = ASN1F_SEQUENCE( 

1901 ASN1F_SEQUENCE( 

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

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

1904 KerberosFlags( 

1905 "apOptions", 

1906 "", 

1907 [ 

1908 "reserved", 

1909 "use-session-key", 

1910 "mutual-required", 

1911 ], 

1912 explicit_tag=0xA2, 

1913 ), 

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

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

1916 ), 

1917 implicit_tag=ASN1_Class_KRB.AP_REQ, 

1918 ) 

1919 

1920 

1921_PADATA_CLASSES[1] = KRB_AP_REQ 

1922 

1923 

1924class KRB_Authenticator(ASN1_Packet): 

1925 ASN1_codec = ASN1_Codecs.BER 

1926 ASN1_root = ASN1F_SEQUENCE( 

1927 ASN1F_SEQUENCE( 

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

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

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

1931 ASN1F_optional( 

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

1933 ), 

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

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

1936 ASN1F_optional( 

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

1938 ), 

1939 ASN1F_optional( 

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

1941 ), 

1942 ASN1F_optional( 

1943 ASN1F_PACKET( 

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

1945 ), 

1946 ), 

1947 ), 

1948 implicit_tag=ASN1_Class_KRB.Authenticator, 

1949 ) 

1950 

1951 

1952# sect 5.5.2 

1953 

1954 

1955class KRB_AP_REP(ASN1_Packet): 

1956 ASN1_codec = ASN1_Codecs.BER 

1957 ASN1_root = ASN1F_SEQUENCE( 

1958 ASN1F_SEQUENCE( 

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

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

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

1962 ), 

1963 implicit_tag=ASN1_Class_KRB.AP_REP, 

1964 ) 

1965 

1966 

1967class EncAPRepPart(ASN1_Packet): 

1968 ASN1_codec = ASN1_Codecs.BER 

1969 ASN1_root = ASN1F_SEQUENCE( 

1970 ASN1F_SEQUENCE( 

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

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

1973 ASN1F_optional( 

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

1975 ), 

1976 ASN1F_optional( 

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

1978 ), 

1979 ), 

1980 implicit_tag=ASN1_Class_KRB.EncAPRepPart, 

1981 ) 

1982 

1983 

1984# sect 5.7 

1985 

1986 

1987class KRB_PRIV(ASN1_Packet): 

1988 ASN1_codec = ASN1_Codecs.BER 

1989 ASN1_root = ASN1F_SEQUENCE( 

1990 ASN1F_SEQUENCE( 

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

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

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

1994 ), 

1995 implicit_tag=ASN1_Class_KRB.PRIV, 

1996 ) 

1997 

1998 

1999class EncKrbPrivPart(ASN1_Packet): 

2000 ASN1_codec = ASN1_Codecs.BER 

2001 ASN1_root = ASN1F_SEQUENCE( 

2002 ASN1F_SEQUENCE( 

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

2004 ASN1F_optional( 

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

2006 ), 

2007 ASN1F_optional( 

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

2009 ), 

2010 ASN1F_optional( 

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

2012 ), 

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

2014 ASN1F_optional( 

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

2016 ), 

2017 ), 

2018 implicit_tag=ASN1_Class_KRB.EncKrbPrivPart, 

2019 ) 

2020 

2021 

2022# sect 5.8 

2023 

2024 

2025class KRB_CRED(ASN1_Packet): 

2026 ASN1_codec = ASN1_Codecs.BER 

2027 ASN1_root = ASN1F_SEQUENCE( 

2028 ASN1F_SEQUENCE( 

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

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

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

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

2033 ), 

2034 implicit_tag=ASN1_Class_KRB.CRED, 

2035 ) 

2036 

2037 

2038class KrbCredInfo(ASN1_Packet): 

2039 ASN1_codec = ASN1_Codecs.BER 

2040 ASN1_root = ASN1F_SEQUENCE( 

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

2042 ASN1F_optional( 

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

2044 ), 

2045 ASN1F_optional( 

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

2047 ), 

2048 ASN1F_optional( 

2049 KerberosFlags( 

2050 "flags", 

2051 None, 

2052 _TICKET_FLAGS, 

2053 explicit_tag=0xA3, 

2054 ), 

2055 ), 

2056 ASN1F_optional( 

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

2058 ), 

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

2060 ASN1F_optional( 

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

2062 ), 

2063 ASN1F_optional( 

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

2065 ), 

2066 ASN1F_optional( 

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

2068 ), 

2069 ASN1F_optional( 

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

2071 ), 

2072 ASN1F_optional( 

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

2074 ), 

2075 ) 

2076 

2077 

2078class EncKrbCredPart(ASN1_Packet): 

2079 ASN1_codec = ASN1_Codecs.BER 

2080 ASN1_root = ASN1F_SEQUENCE( 

2081 ASN1F_SEQUENCE( 

2082 ASN1F_SEQUENCE_OF( 

2083 "ticketInfo", 

2084 [KrbCredInfo()], 

2085 KrbCredInfo, 

2086 explicit_tag=0xA0, 

2087 ), 

2088 ASN1F_optional( 

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

2090 ), 

2091 ASN1F_optional( 

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

2093 ), 

2094 ASN1F_optional( 

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

2096 ), 

2097 ASN1F_optional( 

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

2099 ), 

2100 ASN1F_optional( 

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

2102 ), 

2103 ), 

2104 implicit_tag=ASN1_Class_KRB.EncKrbCredPart, 

2105 ) 

2106 

2107 

2108# sect 5.9.1 

2109 

2110 

2111class MethodData(ASN1_Packet): 

2112 ASN1_codec = ASN1_Codecs.BER 

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

2114 

2115 

2116class _KRBERROR_data_Field(ASN1F_STRING_PacketField): 

2117 def m2i(self, pkt, s): 

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

2119 if not val[0].val: 

2120 return val 

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

2122 # 14: KDC_ERR_ETYPE_NOSUPP 

2123 # 24: KDC_ERR_PREAUTH_FAILED 

2124 # 25: KDC_ERR_PREAUTH_REQUIRED 

2125 # 36: KRB_AP_ERR_BADMATCH 

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

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

2128 # 6: KDC_ERR_C_PRINCIPAL_UNKNOWN 

2129 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

2130 # 12: KDC_ERR_POLICY 

2131 # 13: KDC_ERR_BADOPTION 

2132 # 18: KDC_ERR_CLIENT_REVOKED 

2133 # 29: KDC_ERR_SVC_UNAVAILABLE 

2134 # 32: KRB_AP_ERR_TKT_EXPIRED 

2135 # 41: KRB_AP_ERR_MODIFIED 

2136 # 60: KRB_ERR_GENERIC 

2137 # 62: KERB_ERR_TYPE_EXTENDED 

2138 try: 

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

2140 except BER_Decoding_Error: 

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

2142 # Some types can also happen in FAST sessions 

2143 # 18: KDC_ERR_CLIENT_REVOKED 

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

2145 elif pkt.errorCode.val == 7: 

2146 # This looks like an undocumented structure. 

2147 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

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

2149 raise 

2150 elif pkt.errorCode.val == 69: 

2151 # KRB_AP_ERR_USER_TO_USER_REQUIRED 

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

2153 return val 

2154 

2155 

2156class KRB_ERROR(ASN1_Packet): 

2157 ASN1_codec = ASN1_Codecs.BER 

2158 ASN1_root = ASN1F_SEQUENCE( 

2159 ASN1F_SEQUENCE( 

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

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

2162 ASN1F_optional( 

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

2164 ), 

2165 ASN1F_optional( 

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

2167 ), 

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

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

2170 ASN1F_enum_INTEGER( 

2171 "errorCode", 

2172 0, 

2173 { 

2174 # RFC4120 sect 7.5.9 

2175 0: "KDC_ERR_NONE", 

2176 1: "KDC_ERR_NAME_EXP", 

2177 2: "KDC_ERR_SERVICE_EXP", 

2178 3: "KDC_ERR_BAD_PVNO", 

2179 4: "KDC_ERR_C_OLD_MAST_KVNO", 

2180 5: "KDC_ERR_S_OLD_MAST_KVNO", 

2181 6: "KDC_ERR_C_PRINCIPAL_UNKNOWN", 

2182 7: "KDC_ERR_S_PRINCIPAL_UNKNOWN", 

2183 8: "KDC_ERR_PRINCIPAL_NOT_UNIQUE", 

2184 9: "KDC_ERR_NULL_KEY", 

2185 10: "KDC_ERR_CANNOT_POSTDATE", 

2186 11: "KDC_ERR_NEVER_VALID", 

2187 12: "KDC_ERR_POLICY", 

2188 13: "KDC_ERR_BADOPTION", 

2189 14: "KDC_ERR_ETYPE_NOSUPP", 

2190 15: "KDC_ERR_SUMTYPE_NOSUPP", 

2191 16: "KDC_ERR_PADATA_TYPE_NOSUPP", 

2192 17: "KDC_ERR_TRTYPE_NOSUPP", 

2193 18: "KDC_ERR_CLIENT_REVOKED", 

2194 19: "KDC_ERR_SERVICE_REVOKED", 

2195 20: "KDC_ERR_TGT_REVOKED", 

2196 21: "KDC_ERR_CLIENT_NOTYET", 

2197 22: "KDC_ERR_SERVICE_NOTYET", 

2198 23: "KDC_ERR_KEY_EXPIRED", 

2199 24: "KDC_ERR_PREAUTH_FAILED", 

2200 25: "KDC_ERR_PREAUTH_REQUIRED", 

2201 26: "KDC_ERR_SERVER_NOMATCH", 

2202 27: "KDC_ERR_MUST_USE_USER2USER", 

2203 28: "KDC_ERR_PATH_NOT_ACCEPTED", 

2204 29: "KDC_ERR_SVC_UNAVAILABLE", 

2205 31: "KRB_AP_ERR_BAD_INTEGRITY", 

2206 32: "KRB_AP_ERR_TKT_EXPIRED", 

2207 33: "KRB_AP_ERR_TKT_NYV", 

2208 34: "KRB_AP_ERR_REPEAT", 

2209 35: "KRB_AP_ERR_NOT_US", 

2210 36: "KRB_AP_ERR_BADMATCH", 

2211 37: "KRB_AP_ERR_SKEW", 

2212 38: "KRB_AP_ERR_BADADDR", 

2213 39: "KRB_AP_ERR_BADVERSION", 

2214 40: "KRB_AP_ERR_MSG_TYPE", 

2215 41: "KRB_AP_ERR_MODIFIED", 

2216 42: "KRB_AP_ERR_BADORDER", 

2217 44: "KRB_AP_ERR_BADKEYVER", 

2218 45: "KRB_AP_ERR_NOKEY", 

2219 46: "KRB_AP_ERR_MUT_FAIL", 

2220 47: "KRB_AP_ERR_BADDIRECTION", 

2221 48: "KRB_AP_ERR_METHOD", 

2222 49: "KRB_AP_ERR_BADSEQ", 

2223 50: "KRB_AP_ERR_INAPP_CKSUM", 

2224 51: "KRB_AP_PATH_NOT_ACCEPTED", 

2225 52: "KRB_ERR_RESPONSE_TOO_BIG", 

2226 60: "KRB_ERR_GENERIC", 

2227 61: "KRB_ERR_FIELD_TOOLONG", 

2228 # RFC4556 

2229 62: "KDC_ERR_CLIENT_NOT_TRUSTED", 

2230 63: "KDC_ERR_KDC_NOT_TRUSTED", 

2231 64: "KDC_ERR_INVALID_SIG", 

2232 65: "KDC_ERR_KEY_TOO_WEAK", 

2233 66: "KDC_ERR_CERTIFICATE_MISMATCH", 

2234 67: "KRB_AP_ERR_NO_TGT", 

2235 68: "KDC_ERR_WRONG_REALM", 

2236 69: "KRB_AP_ERR_USER_TO_USER_REQUIRED", 

2237 70: "KDC_ERR_CANT_VERIFY_CERTIFICATE", 

2238 71: "KDC_ERR_INVALID_CERTIFICATE", 

2239 72: "KDC_ERR_REVOKED_CERTIFICATE", 

2240 73: "KDC_ERR_REVOCATION_STATUS_UNKNOWN", 

2241 74: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE", 

2242 75: "KDC_ERR_CLIENT_NAME_MISMATCH", 

2243 76: "KDC_ERR_KDC_NAME_MISMATCH", 

2244 77: "KDC_ERR_INCONSISTENT_KEY_PURPOSE", 

2245 78: "KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED", 

2246 79: "KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED", 

2247 80: "KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED", 

2248 81: "KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED", 

2249 # draft-ietf-kitten-iakerb 

2250 85: "KRB_AP_ERR_IAKERB_KDC_NOT_FOUND", 

2251 86: "KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE", 

2252 # RFC6113 

2253 90: "KDC_ERR_PREAUTH_EXPIRED", 

2254 91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED", 

2255 92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET", 

2256 93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS", 

2257 # RFC8636 

2258 100: "KDC_ERR_NO_ACCEPTABLE_KDF", 

2259 }, 

2260 explicit_tag=0xA6, 

2261 ), 

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

2263 ASN1F_optional( 

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

2265 ), 

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

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

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

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

2270 ), 

2271 implicit_tag=ASN1_Class_KRB.ERROR, 

2272 ) 

2273 

2274 def getSPN(self): 

2275 return "%s@%s" % ( 

2276 self.sname.toString(), 

2277 self.realm.val.decode(), 

2278 ) 

2279 

2280 

2281# PA-FX-ERROR 

2282_PADATA_CLASSES[137] = KRB_ERROR 

2283 

2284 

2285# [MS-KILE] sect 2.2.1 

2286 

2287 

2288class KERB_EXT_ERROR(Packet): 

2289 fields_desc = [ 

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

2291 XLEIntField("reserved", 0), 

2292 XLEIntField("flags", 0x00000001), 

2293 ] 

2294 

2295 

2296# [MS-KILE] sect 2.2.2 

2297 

2298 

2299class _Error_Field(ASN1F_STRING_PacketField): 

2300 def m2i(self, pkt, s): 

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

2302 if not val[0].val: 

2303 return val 

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

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

2306 return val 

2307 

2308 

2309class KERB_ERROR_DATA(ASN1_Packet): 

2310 ASN1_codec = ASN1_Codecs.BER 

2311 ASN1_root = ASN1F_SEQUENCE( 

2312 ASN1F_enum_INTEGER( 

2313 "dataType", 

2314 2, 

2315 { 

2316 1: "KERB_AP_ERR_TYPE_NTSTATUS", # from the wdk 

2317 2: "KERB_AP_ERR_TYPE_SKEW_RECOVERY", 

2318 3: "KERB_ERR_TYPE_EXTENDED", 

2319 }, 

2320 explicit_tag=0xA1, 

2321 ), 

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

2323 ) 

2324 

2325 

2326# This looks like an undocumented structure. 

2327 

2328 

2329class KERB_ERROR_UNK(ASN1_Packet): 

2330 ASN1_codec = ASN1_Codecs.BER 

2331 ASN1_root = ASN1F_SEQUENCE( 

2332 ASN1F_SEQUENCE( 

2333 ASN1F_enum_INTEGER( 

2334 "dataType", 

2335 0, 

2336 { 

2337 -128: "KDC_ERR_MUST_USE_USER2USER", 

2338 }, 

2339 explicit_tag=0xA0, 

2340 ), 

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

2342 ) 

2343 ) 

2344 

2345 

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

2347 

2348 

2349class KRB_TGT_REQ(ASN1_Packet): 

2350 ASN1_codec = ASN1_Codecs.BER 

2351 ASN1_root = ASN1F_SEQUENCE( 

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

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

2354 ASN1F_optional( 

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

2356 ), 

2357 ASN1F_optional( 

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

2359 ), 

2360 ) 

2361 

2362 

2363class KRB_TGT_REP(ASN1_Packet): 

2364 ASN1_codec = ASN1_Codecs.BER 

2365 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

2369 ) 

2370 

2371 

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

2373 

2374 

2375class KRB_FINISHED(ASN1_Packet): 

2376 ASN1_codec = ASN1_Codecs.BER 

2377 ASN1_root = ASN1F_SEQUENCE( 

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

2379 ) 

2380 

2381 

2382# RFC 6542 sect 3.1 

2383 

2384 

2385class KRB_GSS_EXT(Packet): 

2386 fields_desc = [ 

2387 IntEnumField( 

2388 "type", 

2389 0, 

2390 { 

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

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

2393 0x00000001: "GSS_EXTS_IAKERB_FINISHED", # not standard 

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

2395 }, 

2396 ), 

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

2398 MultipleTypeField( 

2399 [ 

2400 ( 

2401 PacketField("data", KRB_FINISHED(), KRB_FINISHED), 

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

2403 ), 

2404 ], 

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

2406 ), 

2407 ] 

2408 

2409 

2410# RFC 4121 sect 4.1.1 

2411 

2412 

2413class KRB_AuthenticatorChecksum(Packet): 

2414 fields_desc = [ 

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

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

2417 FlagsField( 

2418 "Flags", 

2419 0, 

2420 -32, 

2421 { 

2422 0x01: "GSS_C_DELEG_FLAG", 

2423 0x02: "GSS_C_MUTUAL_FLAG", 

2424 0x04: "GSS_C_REPLAY_FLAG", 

2425 0x08: "GSS_C_SEQUENCE_FLAG", 

2426 0x10: "GSS_C_CONF_FLAG", # confidentiality 

2427 0x20: "GSS_C_INTEG_FLAG", # integrity 

2428 # RFC4757 

2429 0x1000: "GSS_C_DCE_STYLE", 

2430 0x2000: "GSS_C_IDENTIFY_FLAG", 

2431 0x4000: "GSS_C_EXTENDED_ERROR_FLAG", 

2432 }, 

2433 ), 

2434 ConditionalField( 

2435 LEShortField("DlgOpt", 1), 

2436 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2437 ), 

2438 ConditionalField( 

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

2440 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2441 ), 

2442 ConditionalField( 

2443 PacketLenField( 

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

2445 ), 

2446 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2447 ), 

2448 # Extensions: RFC 6542 sect 3.1 

2449 PacketListField("Exts", KRB_GSS_EXT(), KRB_GSS_EXT), 

2450 ] 

2451 

2452 

2453# Kerberos V5 GSS-API - RFC1964 and RFC4121 

2454 

2455_TOK_IDS = { 

2456 # RFC 1964 

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

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

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

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

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

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

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

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

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

2466 # RFC 4121 

2467 b"\x04\x04": "GSS_GetMIC", 

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

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

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

2471} 

2472_SGN_ALGS = { 

2473 0x00: "DES MAC MD5", 

2474 0x01: "MD2.5", 

2475 0x02: "DES MAC", 

2476 # RFC 4757 

2477 0x11: "HMAC", 

2478} 

2479_SEAL_ALGS = { 

2480 0: "DES", 

2481 0xFFFF: "none", 

2482 # RFC 4757 

2483 0x10: "RC4", 

2484} 

2485 

2486 

2487# RFC 1964 - sect 1.1 

2488 

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

2490_InitialContextTokens = {} # filled below 

2491 

2492 

2493class KRB_InnerToken(Packet): 

2494 name = "Kerberos v5 InnerToken" 

2495 fields_desc = [ 

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

2497 PacketField( 

2498 "root", 

2499 KRB_AP_REQ(), 

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

2501 ), 

2502 ] 

2503 

2504 def mysummary(self): 

2505 return self.sprintf( 

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

2507 ) 

2508 

2509 def guess_payload_class(self, payload): 

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

2511 return conf.padding_layer 

2512 return Kerberos 

2513 

2514 @classmethod 

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

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

2517 # Older RFC1964 variants of the token have KRB_GSSAPI_Token wrapper 

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

2519 return KRB_GSSAPI_Token 

2520 return cls 

2521 

2522 

2523# RFC 4121 - sect 4.1 

2524 

2525 

2526class KRB_GSSAPI_Token(GSSAPI_BLOB): 

2527 name = "Kerberos GSSAPI-Token" 

2528 ASN1_codec = ASN1_Codecs.BER 

2529 ASN1_root = ASN1F_SEQUENCE( 

2530 ASN1F_OID("MechType", "1.2.840.113554.1.2.2"), 

2531 ASN1F_PACKET( 

2532 "innerToken", 

2533 KRB_InnerToken(), 

2534 KRB_InnerToken, 

2535 implicit_tag=0x0, 

2536 ), 

2537 implicit_tag=ASN1_Class_KRB.Token, 

2538 ) 

2539 

2540 

2541# RFC 1964 - sect 1.2.1 

2542 

2543 

2544class KRB_GSS_MIC_RFC1964(Packet): 

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

2546 fields_desc = [ 

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

2548 XLEIntField("Filler", 0xFFFFFFFF), 

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

2550 PadField( # sect 1.2.2.3 

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

2552 align=8, 

2553 padwith=b"\x04", 

2554 ), 

2555 ] 

2556 

2557 def default_payload_class(self, payload): 

2558 return conf.padding_layer 

2559 

2560 

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

2562 

2563# RFC 1964 - sect 1.2.2 

2564 

2565 

2566class KRB_GSS_Wrap_RFC1964(Packet): 

2567 name = "Kerberos v5 GSS_Wrap (RFC1964)" 

2568 fields_desc = [ 

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

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

2571 XLEShortField("Filler", 0xFFFF), 

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

2573 PadField( # sect 1.2.2.3 

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

2575 align=8, 

2576 padwith=b"\x04", 

2577 ), 

2578 # sect 1.2.2.3 

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

2580 ] 

2581 

2582 def default_payload_class(self, payload): 

2583 return conf.padding_layer 

2584 

2585 

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

2587 

2588 

2589# RFC 1964 - sect 1.2.2 

2590 

2591 

2592class KRB_GSS_Delete_sec_context_RFC1964(Packet): 

2593 name = "Kerberos v5 GSS_Delete_sec_context (RFC1964)" 

2594 fields_desc = KRB_GSS_MIC_RFC1964.fields_desc 

2595 

2596 

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

2598 

2599 

2600# RFC 4121 - sect 4.2.2 

2601_KRB5_GSS_Flags = [ 

2602 "SentByAcceptor", 

2603 "Sealed", 

2604 "AcceptorSubkey", 

2605] 

2606 

2607 

2608# RFC 4121 - sect 4.2.6.1 

2609 

2610 

2611class KRB_GSS_MIC(Packet): 

2612 name = "Kerberos v5 MIC Token" 

2613 fields_desc = [ 

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

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

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

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

2618 ] 

2619 

2620 def default_payload_class(self, payload): 

2621 return conf.padding_layer 

2622 

2623 

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

2625 

2626 

2627# RFC 4121 - sect 4.2.6.2 

2628 

2629 

2630class KRB_GSS_Wrap(Packet): 

2631 name = "Kerberos v5 Wrap Token" 

2632 fields_desc = [ 

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

2634 XByteField("Filler", 0xFF), 

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

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

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

2638 MultipleTypeField( 

2639 [ 

2640 ( 

2641 XStrField("Data", b""), 

2642 lambda pkt: pkt.Flags.Sealed, 

2643 ) 

2644 ], 

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

2646 ), 

2647 ] 

2648 

2649 def default_payload_class(self, payload): 

2650 return conf.padding_layer 

2651 

2652 

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

2654 

2655 

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

2657 

2658 

2659class IAKERB_HEADER(ASN1_Packet): 

2660 ASN1_codec = ASN1_Codecs.BER 

2661 ASN1_root = ASN1F_SEQUENCE( 

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

2663 ASN1F_optional( 

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

2665 ), 

2666 ) 

2667 

2668 

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

2670 

2671 

2672# Register for GSSAPI 

2673 

2674# Kerberos 5 

2675_GSSAPI_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2676_GSSAPI_SIGNATURE_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2677# Kerberos 5 - U2U 

2678_GSSAPI_OIDS["1.2.840.113554.1.2.2.3"] = KRB_InnerToken 

2679# Kerberos 5 - IAKERB 

2680_GSSAPI_OIDS["1.3.6.1.5.2.5"] = KRB_InnerToken 

2681 

2682 

2683# Entry class 

2684 

2685# RFC4120 sect 5.10 

2686 

2687 

2688class Kerberos(ASN1_Packet): 

2689 ASN1_codec = ASN1_Codecs.BER 

2690 ASN1_root = ASN1F_CHOICE( 

2691 "root", 

2692 None, 

2693 # RFC4120 

2694 KRB_GSSAPI_Token, # [APPLICATION 0] 

2695 KRB_Ticket, # [APPLICATION 1] 

2696 KRB_Authenticator, # [APPLICATION 2] 

2697 KRB_AS_REQ, # [APPLICATION 10] 

2698 KRB_AS_REP, # [APPLICATION 11] 

2699 KRB_TGS_REQ, # [APPLICATION 12] 

2700 KRB_TGS_REP, # [APPLICATION 13] 

2701 KRB_AP_REQ, # [APPLICATION 14] 

2702 KRB_AP_REP, # [APPLICATION 15] 

2703 # RFC4120 

2704 KRB_ERROR, # [APPLICATION 30] 

2705 ) 

2706 

2707 def mysummary(self): 

2708 return self.root.summary() 

2709 

2710 

2711bind_bottom_up(UDP, Kerberos, sport=88) 

2712bind_bottom_up(UDP, Kerberos, dport=88) 

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

2714 

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

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

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

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

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

2720 

2721 

2722# RFC4120 sect 7.2.2 

2723 

2724 

2725class KerberosTCPHeader(Packet): 

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

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

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

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

2730 

2731 @classmethod 

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

2733 if len(data) < 4: 

2734 return None 

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

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

2737 return cls(data) 

2738 

2739 

2740bind_layers(KerberosTCPHeader, Kerberos) 

2741 

2742bind_bottom_up(TCP, KerberosTCPHeader, sport=88) 

2743bind_layers(TCP, KerberosTCPHeader, dport=88) 

2744 

2745 

2746# RFC3244 sect 2 

2747 

2748 

2749class KPASSWD_REQ(Packet): 

2750 fields_desc = [ 

2751 ShortField("len", None), 

2752 ShortField("pvno", 0xFF80), 

2753 ShortField("apreqlen", None), 

2754 PacketLenField( 

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

2756 ), 

2757 ConditionalField( 

2758 PacketLenField( 

2759 "krbpriv", 

2760 KRB_PRIV(), 

2761 KRB_PRIV, 

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

2763 ), 

2764 lambda pkt: pkt.apreqlen != 0, 

2765 ), 

2766 ConditionalField( 

2767 PacketLenField( 

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

2769 ), 

2770 lambda pkt: pkt.apreqlen == 0, 

2771 ), 

2772 ] 

2773 

2774 def post_build(self, p, pay): 

2775 if self.len is None: 

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

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

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

2779 return p + pay 

2780 

2781 

2782class ChangePasswdData(ASN1_Packet): 

2783 ASN1_codec = ASN1_Codecs.BER 

2784 ASN1_root = ASN1F_SEQUENCE( 

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

2786 ASN1F_optional( 

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

2788 ), 

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

2790 ) 

2791 

2792 

2793class KPASSWD_REP(Packet): 

2794 fields_desc = [ 

2795 ShortField("len", None), 

2796 ShortField("pvno", 0x0001), 

2797 ShortField("apreplen", None), 

2798 PacketLenField( 

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

2800 ), 

2801 ConditionalField( 

2802 PacketLenField( 

2803 "krbpriv", 

2804 KRB_PRIV(), 

2805 KRB_PRIV, 

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

2807 ), 

2808 lambda pkt: pkt.apreplen != 0, 

2809 ), 

2810 ConditionalField( 

2811 PacketLenField( 

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

2813 ), 

2814 lambda pkt: pkt.apreplen == 0, 

2815 ), 

2816 ] 

2817 

2818 def post_build(self, p, pay): 

2819 if self.len is None: 

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

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

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

2823 return p + pay 

2824 

2825 def answers(self, other): 

2826 return isinstance(other, KPASSWD_REQ) 

2827 

2828 

2829KPASSWD_RESULTS = { 

2830 0: "KRB5_KPASSWD_SUCCESS", 

2831 1: "KRB5_KPASSWD_MALFORMED", 

2832 2: "KRB5_KPASSWD_HARDERROR", 

2833 3: "KRB5_KPASSWD_AUTHERROR", 

2834 4: "KRB5_KPASSWD_SOFTERROR", 

2835 5: "KRB5_KPASSWD_ACCESSDENIED", 

2836 6: "KRB5_KPASSWD_BAD_VERSION", 

2837 7: "KRB5_KPASSWD_INITIAL_FLAG_NEEDED", 

2838} 

2839 

2840 

2841class KPasswdRepData(Packet): 

2842 fields_desc = [ 

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

2844 StrField("resultString", ""), 

2845 ] 

2846 

2847 

2848class Kpasswd(Packet): 

2849 @classmethod 

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

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

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

2853 return KPASSWD_REQ 

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

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

2856 if asn1_tag == 14: 

2857 return KPASSWD_REQ 

2858 elif asn1_tag == 15: 

2859 return KPASSWD_REP 

2860 return KPASSWD_REQ 

2861 

2862 

2863bind_bottom_up(UDP, Kpasswd, sport=464) 

2864bind_bottom_up(UDP, Kpasswd, dport=464) 

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

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

2867 

2868 

2869class KpasswdTCPHeader(Packet): 

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

2871 

2872 @classmethod 

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

2874 if len(data) < 4: 

2875 return None 

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

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

2878 return cls(data) 

2879 

2880 

2881bind_layers(KpasswdTCPHeader, Kpasswd) 

2882 

2883bind_bottom_up(TCP, KpasswdTCPHeader, sport=464) 

2884bind_layers(TCP, KpasswdTCPHeader, dport=464) 

2885 

2886# [MS-KKDCP] 

2887 

2888 

2889class _KerbMessage_Field(ASN1F_STRING_PacketField): 

2890 def m2i(self, pkt, s): 

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

2892 if not val[0].val: 

2893 return val 

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

2895 

2896 

2897class KDC_PROXY_MESSAGE(ASN1_Packet): 

2898 ASN1_codec = ASN1_Codecs.BER 

2899 ASN1_root = ASN1F_SEQUENCE( 

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

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

2902 ASN1F_optional( 

2903 ASN1F_FLAGS( 

2904 "dclocatorHint", 

2905 None, 

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

2907 explicit_tag=0xA2, 

2908 ) 

2909 ), 

2910 ) 

2911 

2912 

2913class KdcProxySocket(SuperSocket): 

2914 """ 

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

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

2917 """ 

2918 

2919 def __init__( 

2920 self, 

2921 url, 

2922 targetDomain, 

2923 dclocatorHint=None, 

2924 no_check_certificate=False, 

2925 **kwargs, 

2926 ): 

2927 self.url = url 

2928 self.targetDomain = targetDomain 

2929 self.dclocatorHint = dclocatorHint 

2930 self.no_check_certificate = no_check_certificate 

2931 self.queue = deque() 

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

2933 

2934 def recv(self, x=None): 

2935 return self.queue.popleft() 

2936 

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

2938 from scapy.layers.http import HTTP_Client 

2939 

2940 cli = HTTP_Client(no_check_certificate=self.no_check_certificate) 

2941 try: 

2942 # sr it via the web client 

2943 resp = cli.request( 

2944 self.url, 

2945 Method="POST", 

2946 data=bytes( 

2947 # Wrap request in KDC_PROXY_MESSAGE 

2948 KDC_PROXY_MESSAGE( 

2949 kerbMessage=bytes(x), 

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

2951 # dclocatorHint is optional 

2952 dclocatorHint=self.dclocatorHint, 

2953 ) 

2954 ), 

2955 http_headers={ 

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

2957 "Pragma": "no-cache", 

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

2959 }, 

2960 ) 

2961 if resp and conf.raw_layer in resp: 

2962 # Parse the payload 

2963 resp = KDC_PROXY_MESSAGE(resp.load).kerbMessage 

2964 # We have an answer, queue it. 

2965 self.queue.append(resp) 

2966 else: 

2967 raise EOFError 

2968 finally: 

2969 cli.close() 

2970 

2971 @staticmethod 

2972 def select(sockets, remain=None): 

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

2974 

2975 

2976# Util functions 

2977 

2978 

2979class PKINIT_KEX_METHOD(IntEnum): 

2980 DIFFIE_HELLMAN = 1 

2981 PUBLIC_KEY = 2 

2982 

2983 

2984class KerberosClient(Automaton): 

2985 """ 

2986 Implementation of a Kerberos client. 

2987 

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

2989 wrap this client. 

2990 

2991 Common parameters: 

2992 

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

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

2995 :param upn: the UPN of the client. 

2996 :param password: the password of the client. 

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

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

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

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

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

3002 

3003 Advanced common parameters: 

3004 

3005 :param kdc_proxy: specify a KDC proxy url 

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

3007 :param fast: use FAST armoring 

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

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

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

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

3012 

3013 AS-REQ only: 

3014 

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

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

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

3018 only the ROOT CA is required. 

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

3020 'password' is the password of the p12. 

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

3022 Certificate based one for PKINIT. 

3023 

3024 TGS-REQ only: 

3025 

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

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

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

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

3030 :param u2u: sets the U2U flag 

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

3032 :param s4u2proxy: sets the S4U2Proxy flag 

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

3034 """ 

3035 

3036 RES_AS_MODE = namedtuple( 

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

3038 ) 

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

3040 

3041 class MODE(IntEnum): 

3042 AS_REQ = 0 

3043 TGS_REQ = 1 

3044 GET_SALT = 2 

3045 

3046 def __init__( 

3047 self, 

3048 mode=MODE.AS_REQ, 

3049 ip: Optional[str] = None, 

3050 upn: Optional[str] = None, 

3051 password: Optional[str] = None, 

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

3053 realm: Optional[str] = None, 

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

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

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

3057 p12: Optional[str] = None, 

3058 spn: Optional[str] = None, 

3059 ticket: Optional[KRB_Ticket] = None, 

3060 host: Optional[str] = None, 

3061 renew: bool = False, 

3062 additional_tickets: List[KRB_Ticket] = [], 

3063 u2u: bool = False, 

3064 for_user: Optional[str] = None, 

3065 s4u2proxy: bool = False, 

3066 dmsa: bool = False, 

3067 kdc_proxy: Optional[str] = None, 

3068 kdc_proxy_no_check_certificate: bool = False, 

3069 fast: bool = False, 

3070 armor_ticket: KRB_Ticket = None, 

3071 armor_ticket_upn: Optional[str] = None, 

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

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

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

3075 pkinit_kex_method: PKINIT_KEX_METHOD = PKINIT_KEX_METHOD.DIFFIE_HELLMAN, 

3076 port: int = 88, 

3077 timeout: int = 5, 

3078 verbose: bool = True, 

3079 **kwargs, 

3080 ): 

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

3082 from scapy.layers.ldap import dclocator 

3083 

3084 if not upn: 

3085 raise ValueError("Invalid upn") 

3086 if not spn: 

3087 raise ValueError("Invalid spn") 

3088 if realm is None: 

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

3090 _, realm = _parse_upn(upn) 

3091 elif mode == self.MODE.TGS_REQ: 

3092 _, realm = _parse_spn(spn) 

3093 if not realm and ticket: 

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

3095 # of the ticket. 

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

3097 else: 

3098 raise ValueError("Invalid realm") 

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 

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

3142 if not host: 

3143 raise ValueError("Invalid host") 

3144 if x509 is not None and (not x509key or not ca): 

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

3146 elif mode == self.MODE.TGS_REQ: 

3147 if not ticket: 

3148 raise ValueError("Invalid ticket") 

3149 

3150 if not ip and not kdc_proxy: 

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

3152 ip = dclocator( 

3153 realm, 

3154 timeout=timeout, 

3155 # Use connect mode instead of ldap for compatibility 

3156 # with MIT kerberos servers 

3157 mode="connect", 

3158 port=port, 

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

3160 ).ip 

3161 

3162 # Armoring checks 

3163 if fast: 

3164 if mode == self.MODE.AS_REQ: 

3165 # Requires an external ticket 

3166 if not armor_ticket or not armor_ticket_upn or not armor_ticket_skey: 

3167 raise ValueError( 

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

3169 "please provide the 3 required armor arguments" 

3170 ) 

3171 elif mode == self.MODE.TGS_REQ: 

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

3173 raise ValueError( 

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

3175 ) 

3176 

3177 if mode == self.MODE.GET_SALT: 

3178 if etypes is not None: 

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

3180 

3181 etypes = [ 

3182 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3183 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3184 ] 

3185 elif etypes is None: 

3186 etypes = [ 

3187 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3188 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3189 EncryptionType.RC4_HMAC, 

3190 EncryptionType.RC4_HMAC_EXP, 

3191 EncryptionType.DES_CBC_MD5, 

3192 ] 

3193 self.etypes = etypes 

3194 

3195 self.mode = mode 

3196 

3197 self.result = None # Result 

3198 

3199 self._timeout = timeout 

3200 self._verbose = verbose 

3201 self._ip = ip 

3202 self._port = port 

3203 self.kdc_proxy = kdc_proxy 

3204 self.kdc_proxy_no_check_certificate = kdc_proxy_no_check_certificate 

3205 

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

3207 self.host = host.upper() 

3208 self.password = password and bytes_encode(password) 

3209 self.spn = spn 

3210 self.upn = upn 

3211 self.realm = realm.upper() 

3212 self.x509 = x509 

3213 self.x509key = x509key 

3214 self.pkinit_kex_method = pkinit_kex_method 

3215 self.ticket = ticket 

3216 self.fast = fast 

3217 self.armor_ticket = armor_ticket 

3218 self.armor_ticket_upn = armor_ticket_upn 

3219 self.armor_ticket_skey = armor_ticket_skey 

3220 self.key_list_req = key_list_req 

3221 self.renew = renew 

3222 self.additional_tickets = additional_tickets # U2U + S4U2Proxy 

3223 self.u2u = u2u # U2U 

3224 self.for_user = for_user # FOR-USER 

3225 self.s4u2proxy = s4u2proxy # S4U2Proxy 

3226 self.dmsa = dmsa # DMSA 

3227 self.key = key 

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

3229 self.replykey = None # Key used for reply 

3230 # See RFC4120 - sect 7.2.2 

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

3232 self.should_followup = False 

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

3234 self.fast_req_sent = False 

3235 # Session parameters 

3236 self.pre_auth = False 

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

3238 self.fast_rep = None 

3239 self.fast_error = None 

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

3241 self.fast_armorkey = None # The armor key 

3242 self.fxcookie = None 

3243 self.pkinit_dh_key = None 

3244 if ca is not None: 

3245 self.pkinit_cms = CMS_Engine(ca) 

3246 else: 

3247 self.pkinit_cms = None 

3248 

3249 sock = self._connect() 

3250 super(KerberosClient, self).__init__( 

3251 sock=sock, 

3252 **kwargs, 

3253 ) 

3254 

3255 def _connect(self): 

3256 """ 

3257 Internal function to bind a socket to the DC. 

3258 This also takes care of an eventual KDC proxy. 

3259 """ 

3260 if self.kdc_proxy: 

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

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

3263 sock = KdcProxySocket( 

3264 url=self.kdc_proxy, 

3265 targetDomain=self.realm, 

3266 no_check_certificate=self.kdc_proxy_no_check_certificate, 

3267 ) 

3268 else: 

3269 sock = socket.socket() 

3270 sock.settimeout(self._timeout) 

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

3272 sock = StreamSocket(sock, KerberosTCPHeader) 

3273 return sock 

3274 

3275 def send(self, pkt): 

3276 """ 

3277 Sends a wrapped Kerberos packet 

3278 """ 

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

3280 

3281 def _show_krb_error(self, error): 

3282 """ 

3283 Displays a Kerberos error 

3284 """ 

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

3286 # KDC_ERR_S_PRINCIPAL_UNKNOWN 

3287 if ( 

3288 isinstance(error.root.eData, KERB_ERROR_UNK) 

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

3290 ): 

3291 log_runtime.error( 

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

3293 ) 

3294 else: 

3295 log_runtime.error( 

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

3297 % error.root.getSPN() 

3298 ) 

3299 else: 

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

3301 if self._verbose: 

3302 error.show() 

3303 

3304 def _base_kdc_req(self, now_time): 

3305 """ 

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

3307 """ 

3308 kdcreq = KRB_KDC_REQ_BODY( 

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

3310 additionalTickets=None, 

3311 # Windows default 

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

3313 cname=None, 

3314 realm=ASN1_GENERAL_STRING(self.realm), 

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

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

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

3318 ) 

3319 if self.renew: 

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

3321 return kdcreq 

3322 

3323 def calc_fast_armorkey(self): 

3324 """ 

3325 Calculate and return the FAST armorkey 

3326 """ 

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

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

3329 # AS-REQ mode 

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

3331 

3332 self.fast_armorkey = KRB_FX_CF2( 

3333 self.fast_skey, 

3334 self.armor_ticket_skey, 

3335 b"subkeyarmor", 

3336 b"ticketarmor", 

3337 ) 

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

3339 # TGS-REQ: 2 cases 

3340 

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

3342 

3343 if not self.armor_ticket: 

3344 # Case 1: Implicit armoring 

3345 self.fast_armorkey = KRB_FX_CF2( 

3346 self.subkey, 

3347 self.key, 

3348 b"subkeyarmor", 

3349 b"ticketarmor", 

3350 ) 

3351 else: 

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

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

3354 

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

3356 

3357 explicit_armor_key = KRB_FX_CF2( 

3358 self.fast_skey, 

3359 self.armor_ticket_skey, 

3360 b"subkeyarmor", 

3361 b"ticketarmor", 

3362 ) 

3363 

3364 self.fast_armorkey = KRB_FX_CF2( 

3365 explicit_armor_key, 

3366 self.subkey, 

3367 b"explicitarmor", 

3368 b"tgsarmor", 

3369 ) 

3370 

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

3372 """ 

3373 :param kdc_req: the KDC_REQ_BODY to wrap 

3374 :param padata: the list of PADATA to wrap 

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

3376 """ 

3377 

3378 # Create the PA Fast request wrapper 

3379 pafastreq = PA_FX_FAST_REQUEST( 

3380 armoredData=KrbFastArmoredReq( 

3381 reqChecksum=Checksum(), 

3382 encFastReq=EncryptedData(), 

3383 ) 

3384 ) 

3385 

3386 if self.armor_ticket is not None: 

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

3388 

3389 pafastreq.armoredData.armor = KrbFastArmor( 

3390 armorType=1, # FX_FAST_ARMOR_AP_REQUEST 

3391 armorValue=KRB_AP_REQ( 

3392 ticket=self.armor_ticket, 

3393 authenticator=EncryptedData(), 

3394 ), 

3395 ) 

3396 

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

3398 _, crealm = _parse_upn(self.armor_ticket_upn) 

3399 authenticator = KRB_Authenticator( 

3400 crealm=ASN1_GENERAL_STRING(crealm), 

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

3402 cksum=None, 

3403 ctime=ASN1_GENERALIZED_TIME(now_time), 

3404 cusec=ASN1_INTEGER(0), 

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

3406 seqNumber=ASN1_INTEGER(0), 

3407 encAuthorizationData=None, 

3408 ) 

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

3410 self.armor_ticket_skey, 

3411 authenticator, 

3412 ) 

3413 

3414 # Sign the fast request wrapper 

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

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

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

3418 pafastreq.armoredData.reqChecksum.make( 

3419 self.fast_armorkey, 

3420 bytes(pa_tgsreq_ap), 

3421 ) 

3422 else: 

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

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

3425 # containing message" 

3426 pafastreq.armoredData.reqChecksum.make( 

3427 self.fast_armorkey, 

3428 bytes(kdc_req), 

3429 ) 

3430 

3431 # Build and encrypt the Fast request 

3432 fastreq = KrbFastReq( 

3433 padata=padata, 

3434 reqBody=kdc_req, 

3435 ) 

3436 pafastreq.armoredData.encFastReq.encrypt( 

3437 self.fast_armorkey, 

3438 fastreq, 

3439 ) 

3440 

3441 # Return the PADATA 

3442 return PADATA( 

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

3444 padataValue=pafastreq, 

3445 ) 

3446 

3447 def as_req(self): 

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

3449 

3450 # 1. Build and populate KDC-REQ 

3451 kdc_req = self._base_kdc_req(now_time=now_time) 

3452 kdc_req.addresses = [ 

3453 HostAddress( 

3454 addrType=ASN1_INTEGER(20), # Netbios 

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

3456 ) 

3457 ] 

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

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

3460 

3461 # 2. Build the list of PADATA 

3462 padata = [ 

3463 PADATA( 

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

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

3466 ) 

3467 ] 

3468 

3469 # Cookie support 

3470 if self.fxcookie: 

3471 padata.insert( 

3472 0, 

3473 PADATA( 

3474 padataType=133, # PA-FX-COOKIE 

3475 padataValue=self.fxcookie, 

3476 ), 

3477 ) 

3478 

3479 # FAST 

3480 if self.fast: 

3481 # Calculate the armor key 

3482 self.calc_fast_armorkey() 

3483 

3484 # [MS-KILE] sect 3.2.5.5 

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

3486 padata.append( 

3487 PADATA( 

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

3489 padataValue=PA_PAC_OPTIONS( 

3490 options="Claims", 

3491 ), 

3492 ) 

3493 ) 

3494 

3495 # Pre-auth is requested 

3496 if self.pre_auth: 

3497 if self.x509: 

3498 # Special PKINIT (RFC4556) factor 

3499 

3500 # RFC4556 - 3.2.1. Generation of Client Request 

3501 

3502 # RFC4556 - 3.2.1 - (5) AuthPack 

3503 authpack = KRB_AuthPack( 

3504 pkAuthenticator=KRB_PKAuthenticator( 

3505 ctime=ASN1_GENERALIZED_TIME(now_time), 

3506 cusec=ASN1_INTEGER(0), 

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

3508 ), 

3509 clientPublicValue=None, # Used only in DH mode 

3510 supportedCMSTypes=None, 

3511 clientDHNonce=None, 

3512 supportedKDFs=None, 

3513 ) 

3514 

3515 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

3516 # RFC4556 - 3.2.3.1. Diffie-Hellman Key Exchange 

3517 

3518 # We use modp2048 

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

3520 self.pkinit_dh_key = dh_parameters.generate_private_key() 

3521 numbers = dh_parameters.parameter_numbers() 

3522 

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

3524 # and we want the DomainParameters format. 

3525 authpack.clientPublicValue = X509_SubjectPublicKeyInfo( 

3526 signatureAlgorithm=X509_AlgorithmIdentifier( 

3527 algorithm=ASN1_OID("dhpublicnumber"), 

3528 parameters=DomainParameters( 

3529 p=ASN1_INTEGER(numbers.p), 

3530 g=ASN1_INTEGER(numbers.g), 

3531 # q: see ERRATA 1 of RFC4556 

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

3533 ), 

3534 ), 

3535 subjectPublicKey=DHPublicKey( 

3536 y=ASN1_INTEGER( 

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

3538 ), 

3539 ), 

3540 ) 

3541 elif self.pkinit_kex_method == PKINIT_KEX_METHOD.PUBLIC_KEY: 

3542 # RFC4556 - 3.2.3.2. - Public Key Encryption 

3543 

3544 # Set supportedCMSTypes, supportedKDFs 

3545 authpack.supportedCMSTypes = [ 

3546 X509_AlgorithmIdentifier(algorithm=ASN1_OID(x)) 

3547 for x in [ 

3548 "ecdsa-with-SHA512", 

3549 "ecdsa-with-SHA256", 

3550 "sha512WithRSAEncryption", 

3551 "sha256WithRSAEncryption", 

3552 ] 

3553 ] 

3554 authpack.supportedKDFs = [ 

3555 KDFAlgorithmId(kdfId=ASN1_OID(x)) 

3556 for x in [ 

3557 "id-pkinit-kdf-sha256", 

3558 "id-pkinit-kdf-sha1", 

3559 "id-pkinit-kdf-sha512", 

3560 ] 

3561 ] 

3562 

3563 # XXX UNFINISHED 

3564 raise NotImplementedError 

3565 else: 

3566 raise ValueError 

3567 

3568 # Populate paChecksum and PAChecksum2 

3569 authpack.pkAuthenticator.make_checksum(bytes(kdc_req)) 

3570 

3571 # Sign the AuthPack 

3572 signedAuthpack = self.pkinit_cms.sign( 

3573 authpack, 

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

3575 self.x509, 

3576 self.x509key, 

3577 ) 

3578 

3579 # Build PA-DATA 

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

3581 pafactor = PADATA( 

3582 padataType=self.pa_type, 

3583 padataValue=PA_PK_AS_REQ( 

3584 signedAuthpack=signedAuthpack, 

3585 trustedCertifiers=None, 

3586 kdcPkId=None, 

3587 ), 

3588 ) 

3589 else: 

3590 # Key-based factor 

3591 

3592 if self.fast: 

3593 # Special FAST factor 

3594 # RFC6113 sect 5.4.6 

3595 

3596 # Calculate the 'challenge key' 

3597 ts_key = KRB_FX_CF2( 

3598 self.fast_armorkey, 

3599 self.key, 

3600 b"clientchallengearmor", 

3601 b"challengelongterm", 

3602 ) 

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

3604 pafactor = PADATA( 

3605 padataType=self.pa_type, 

3606 padataValue=EncryptedData(), 

3607 ) 

3608 else: 

3609 # Usual 'timestamp' factor 

3610 ts_key = self.key 

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

3612 pafactor = PADATA( 

3613 padataType=self.pa_type, 

3614 padataValue=EncryptedData(), 

3615 ) 

3616 pafactor.padataValue.encrypt( 

3617 ts_key, 

3618 PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), 

3619 ) 

3620 

3621 # Insert Pre-Authentication data 

3622 padata.insert( 

3623 0, 

3624 pafactor, 

3625 ) 

3626 

3627 # FAST support 

3628 if self.fast: 

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

3630 # hidden inside the encrypted section. 

3631 padata = [ 

3632 self._fast_wrap( 

3633 kdc_req=kdc_req, 

3634 padata=padata, 

3635 now_time=now_time, 

3636 ) 

3637 ] 

3638 

3639 # 3. Build the request 

3640 asreq = Kerberos( 

3641 root=KRB_AS_REQ( 

3642 padata=padata, 

3643 reqBody=kdc_req, 

3644 ) 

3645 ) 

3646 

3647 # Note the reply key 

3648 self.replykey = self.key 

3649 

3650 return asreq 

3651 

3652 def tgs_req(self): 

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

3654 

3655 # Compute armor key for FAST 

3656 if self.fast: 

3657 self.calc_fast_armorkey() 

3658 

3659 # 1. Build and populate KDC-REQ 

3660 kdc_req = self._base_kdc_req(now_time=now_time) 

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

3662 

3663 # Additional tickets 

3664 if self.additional_tickets: 

3665 kdc_req.additionalTickets = self.additional_tickets 

3666 

3667 # U2U 

3668 if self.u2u: 

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

3670 

3671 # 2. Build the list of PADATA 

3672 padata = [] 

3673 

3674 # [MS-SFU] FOR-USER extension 

3675 if self.for_user is not None: 

3676 # [MS-SFU] note 4: 

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

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

3679 # certificate is available. 

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

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

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

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

3684 

3685 # 1. Add PA_S4U_X509_USER 

3686 pasfux509 = PA_S4U_X509_USER( 

3687 userId=S4UUserID( 

3688 nonce=kdc_req.nonce, 

3689 # [MS-SFU] note 5: 

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

3691 options="USE_REPLY_KEY_USAGE", 

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

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

3694 subjectCertificate=None, # TODO 

3695 ), 

3696 checksum=Checksum(), 

3697 ) 

3698 

3699 if self.dmsa: 

3700 # DMSA = set UNCONDITIONAL_DELEGATION to 1 

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

3702 

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

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

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

3706 pasfux509.checksum.make( 

3707 self.key, 

3708 bytes(pasfux509.userId), 

3709 cksumtype=ChecksumType.RSA_MD4, 

3710 ) 

3711 else: 

3712 pasfux509.checksum.make( 

3713 self.key, 

3714 bytes(pasfux509.userId), 

3715 ) 

3716 padata.append( 

3717 PADATA( 

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

3719 padataValue=pasfux509, 

3720 ) 

3721 ) 

3722 

3723 # 2. Add PA_FOR_USER 

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

3725 paforuser = PA_FOR_USER( 

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

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

3728 cksum=Checksum(), 

3729 ) 

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

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

3732 ) + ( 

3733 ( 

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

3735 + paforuser.userRealm.val 

3736 + paforuser.authPackage.val 

3737 ).encode() 

3738 ) 

3739 paforuser.cksum.make( 

3740 self.key, 

3741 S4UByteArray, 

3742 cksumtype=ChecksumType.HMAC_MD5, 

3743 ) 

3744 padata.append( 

3745 PADATA( 

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

3747 padataValue=paforuser, 

3748 ) 

3749 ) 

3750 

3751 # [MS-SFU] S4U2proxy - sect 3.1.5.2.1 

3752 if self.s4u2proxy: 

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

3754 padata.append( 

3755 PADATA( 

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

3757 padataValue=PA_PAC_OPTIONS( 

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

3759 ), 

3760 ) 

3761 ) 

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

3763 kdc_req.kdcOptions.set(14, 1) 

3764 

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

3766 if self.key_list_req: 

3767 padata.append( 

3768 PADATA( 

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

3770 padataValue=KERB_KEY_LIST_REQ( 

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

3772 ), 

3773 ) 

3774 ) 

3775 

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

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

3778 pa_tgs_req = PADATA( 

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

3780 padataValue=apreq, 

3781 ) 

3782 

3783 # 4. Populate it's authenticator 

3784 _, crealm = _parse_upn(self.upn) 

3785 authenticator = KRB_Authenticator( 

3786 crealm=ASN1_GENERAL_STRING(crealm), 

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

3788 cksum=None, 

3789 ctime=ASN1_GENERALIZED_TIME(now_time), 

3790 cusec=ASN1_INTEGER(0), 

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

3792 seqNumber=None, 

3793 encAuthorizationData=None, 

3794 ) 

3795 

3796 # Compute checksum 

3797 if self.key.cksumtype: 

3798 authenticator.cksum = Checksum() 

3799 authenticator.cksum.make( 

3800 self.key, 

3801 bytes(kdc_req), 

3802 ) 

3803 

3804 # Encrypt authenticator 

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

3806 

3807 # 5. Process FAST if required 

3808 if self.fast: 

3809 padata = [ 

3810 self._fast_wrap( 

3811 kdc_req=kdc_req, 

3812 padata=padata, 

3813 now_time=now_time, 

3814 pa_tgsreq_ap=apreq, 

3815 ) 

3816 ] 

3817 

3818 # 6. Add the final PADATA 

3819 padata.append(pa_tgs_req) 

3820 

3821 # 7. Build the request 

3822 tgsreq = Kerberos( 

3823 root=KRB_TGS_REQ( 

3824 padata=padata, 

3825 reqBody=kdc_req, 

3826 ) 

3827 ) 

3828 

3829 # Note the reply key 

3830 if self.subkey: 

3831 self.replykey = self.subkey 

3832 else: 

3833 self.replykey = self.key 

3834 

3835 return tgsreq 

3836 

3837 @ATMT.state(initial=1) 

3838 def BEGIN(self): 

3839 pass 

3840 

3841 @ATMT.condition(BEGIN) 

3842 def should_send_as_req(self): 

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

3844 raise self.SENT_AS_REQ() 

3845 

3846 @ATMT.condition(BEGIN) 

3847 def should_send_tgs_req(self): 

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

3849 raise self.SENT_TGS_REQ() 

3850 

3851 @ATMT.action(should_send_as_req) 

3852 def send_as_req(self): 

3853 self.send(self.as_req()) 

3854 

3855 @ATMT.action(should_send_tgs_req) 

3856 def send_tgs_req(self): 

3857 self.send(self.tgs_req()) 

3858 

3859 @ATMT.state() 

3860 def SENT_AS_REQ(self): 

3861 pass 

3862 

3863 @ATMT.state() 

3864 def SENT_TGS_REQ(self): 

3865 pass 

3866 

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

3868 """ 

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

3870 

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

3872 """ 

3873 salt = b"" 

3874 

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

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

3877 

3878 # 1. Process pa-data 

3879 if padatas is not None: 

3880 for padata in padatas: 

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

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

3883 elt = padata.padataValue.seq[0] 

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

3885 etype = elt.etype.val 

3886 if etype != EncryptionType.RC4_HMAC: 

3887 salt = elt.salt.val 

3888 

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

3890 # PKINIT handling 

3891 

3892 # The steps are as follows: 

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

3894 # is different depending on the used method. 

3895 # 2. Compute the replykey 

3896 

3897 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

3898 # Unpack KDCDHKeyInfo 

3899 keyinfo = self.pkinit_cms.verify( 

3900 padata.padataValue.rep.dhSignedData, 

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

3902 ) 

3903 

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

3905 # the CMS successfully, end here. 

3906 if etype is None: 

3907 continue 

3908 

3909 # Extract crypto parameters 

3910 y = keyinfo.subjectPublicKey.y.val 

3911 

3912 # Import into cryptography 

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

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

3915 

3916 # Calculate DHSharedSecret 

3917 DHSharedSecret = self.pkinit_dh_key.exchange(pubkey) 

3918 

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

3920 self.replykey = octetstring2key( 

3921 etype, 

3922 DHSharedSecret, 

3923 ) 

3924 

3925 else: 

3926 raise ValueError 

3927 

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

3929 # Get cookie and store it 

3930 self.fxcookie = padata.padataValue 

3931 

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

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

3934 if isinstance(padata.padataValue, PA_FX_FAST_REPLY): 

3935 self.fast_rep = ( 

3936 padata.padataValue.armoredData.encFastRep.decrypt( 

3937 self.fast_armorkey, 

3938 ) 

3939 ) 

3940 

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

3942 # Get error and store it 

3943 self.fast_error = padata.padataValue 

3944 

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

3946 # Verify S4U checksum 

3947 key_usage_number = None 

3948 pasfux509 = padata.padataValue 

3949 # [MS-SFU] sect 2.2.2 

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

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

3952 key_usage_number = 27 

3953 pasfux509.checksum.verify( 

3954 self.key, 

3955 bytes(pasfux509.userId), 

3956 key_usage_number=key_usage_number, 

3957 ) 

3958 

3959 # 2. Update the current keys if necessary 

3960 

3961 # Compute client key if not already provided 

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

3963 self.key = Key.string_to_key( 

3964 etype, 

3965 self.password, 

3966 salt, 

3967 ) 

3968 

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

3970 if self.fast_rep and self.fast_rep.strengthenKey: 

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

3972 self.replykey = KRB_FX_CF2( 

3973 self.fast_rep.strengthenKey.toKey(), 

3974 self.replykey, 

3975 b"strengthenkey", 

3976 b"replykey", 

3977 ) 

3978 

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

3980 def receive_salt_mode(self, pkt): 

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

3982 # exit. 

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

3984 if Kerberos not in pkt: 

3985 raise self.FINAL() 

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

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

3988 raise self.FINAL() 

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

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

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

3992 elt = padata.padataValue.seq[0] 

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

3994 self.result = elt.salt.val 

3995 raise self.FINAL() 

3996 else: 

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

3998 raise self.FINAL() 

3999 

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

4001 def receive_krb_error_as_req(self, pkt): 

4002 # We check for Kerberos errors. 

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

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

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

4006 # Process PAs if available 

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

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

4009 

4010 # Special case for FAST errors 

4011 if self.fast_rep: 

4012 # This is actually a fast response error ! 

4013 frep, self.fast_rep = self.fast_rep, None 

4014 # Re-process PAs 

4015 self._process_padatas_and_key(frep.padata) 

4016 # Extract real Kerberos error from FAST message 

4017 ferr = Kerberos(root=self.fast_error) 

4018 self.fast_error = None 

4019 # Recurse 

4020 self.receive_krb_error_as_req(ferr) 

4021 return 

4022 

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

4024 if not self.key and not self.x509: 

4025 log_runtime.error( 

4026 "Got 'KDC_ERR_PREAUTH_REQUIRED', " 

4027 "but no possible key could be computed." 

4028 ) 

4029 raise self.FINAL() 

4030 self.should_followup = True 

4031 self.pre_auth = True 

4032 raise self.BEGIN() 

4033 else: 

4034 self._show_krb_error(pkt) 

4035 raise self.FINAL() 

4036 

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

4038 def receive_as_rep(self, pkt): 

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

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

4041 

4042 @ATMT.eof(SENT_AS_REQ) 

4043 def retry_after_eof_in_apreq(self): 

4044 if self.should_followup: 

4045 # Reconnect and Restart 

4046 self.should_followup = False 

4047 self.update_sock(self._connect()) 

4048 raise self.BEGIN() 

4049 else: 

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

4051 raise self.FINAL() 

4052 

4053 @ATMT.action(receive_as_rep) 

4054 def decrypt_as_rep(self, pkt): 

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

4056 self._process_padatas_and_key( 

4057 pkt.root.padata, 

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

4059 ) 

4060 

4061 if not self.pre_auth: 

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

4063 

4064 # Process FAST response 

4065 if self.fast_rep: 

4066 # Verify the ticket-checksum 

4067 self.fast_rep.finished.ticketChecksum.verify( 

4068 self.fast_armorkey, 

4069 bytes(pkt.root.ticket), 

4070 ) 

4071 self.fast_rep = None 

4072 elif self.fast: 

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

4074 

4075 # Check for PKINIT 

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

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

4078 

4079 # Decrypt AS-REP response 

4080 enc = pkt.root.encPart 

4081 res = enc.decrypt(self.replykey) 

4082 self.result = self.RES_AS_MODE( 

4083 pkt.root, 

4084 res.key.toKey(), 

4085 res, 

4086 pkt.root.getUPN(), 

4087 self.pa_type, 

4088 ) 

4089 

4090 @ATMT.receive_condition(SENT_TGS_REQ) 

4091 def receive_krb_error_tgs_req(self, pkt): 

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

4093 # Process PAs if available 

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

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

4096 

4097 if self.fast_rep: 

4098 # This is actually a fast response error ! 

4099 frep, self.fast_rep = self.fast_rep, None 

4100 # Re-process PAs 

4101 self._process_padatas_and_key(frep.padata) 

4102 # Extract real Kerberos error from FAST message 

4103 ferr = Kerberos(root=self.fast_error) 

4104 self.fast_error = None 

4105 # Recurse 

4106 self.receive_krb_error_tgs_req(ferr) 

4107 return 

4108 

4109 self._show_krb_error(pkt) 

4110 raise self.FINAL() 

4111 

4112 @ATMT.receive_condition(SENT_TGS_REQ) 

4113 def receive_tgs_rep(self, pkt): 

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

4115 if ( 

4116 not self.renew 

4117 and not self.dmsa 

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

4119 ): 

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

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

4122 

4123 @ATMT.action(receive_tgs_rep) 

4124 def decrypt_tgs_rep(self, pkt): 

4125 self._process_padatas_and_key(pkt.root.padata) 

4126 

4127 # Process FAST response 

4128 if self.fast_rep: 

4129 # Verify the ticket-checksum 

4130 self.fast_rep.finished.ticketChecksum.verify( 

4131 self.fast_armorkey, 

4132 bytes(pkt.root.ticket), 

4133 ) 

4134 self.fast_rep = None 

4135 elif self.fast: 

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

4137 

4138 # Decrypt TGS-REP response 

4139 enc = pkt.root.encPart 

4140 if self.subkey: 

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

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

4143 # authenticator subkey is used." 

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

4145 else: 

4146 res = enc.decrypt(self.replykey) 

4147 

4148 # Store result 

4149 self.result = self.RES_TGS_MODE( 

4150 pkt.root, 

4151 res.key.toKey(), 

4152 res, 

4153 self.upn, 

4154 ) 

4155 

4156 @ATMT.state(final=1) 

4157 def FINAL(self): 

4158 pass 

4159 

4160 

4161def _parse_upn(upn): 

4162 """ 

4163 Extract the username and realm from full UPN 

4164 """ 

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

4166 if not m: 

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

4168 if "/" in upn: 

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

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

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

4172 raise ValueError(err) 

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

4174 user = m.group(1) 

4175 domain = m.group(3) 

4176 else: 

4177 user = m.group(3) 

4178 domain = m.group(1) 

4179 return user, domain 

4180 

4181 

4182def _parse_spn(spn): 

4183 """ 

4184 Extract ServiceName and realm from full SPN 

4185 """ 

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

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

4188 if not m: 

4189 try: 

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

4191 return _parse_upn(spn) 

4192 except ValueError: 

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

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

4195 

4196 

4197def _spn_are_equal(spn1, spn2): 

4198 """ 

4199 Check that two SPNs are equal. 

4200 """ 

4201 spn1, _ = _parse_spn(spn1) 

4202 spn2, _ = _parse_spn(spn2) 

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

4204 

4205 

4206def krb_as_req( 

4207 upn: str, 

4208 spn: Optional[str] = None, 

4209 ip: Optional[str] = None, 

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

4211 password: Optional[str] = None, 

4212 realm: Optional[str] = None, 

4213 host: str = "WIN10", 

4214 p12: Optional[str] = None, 

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

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

4217 **kwargs, 

4218): 

4219 r""" 

4220 Kerberos AS-Req 

4221 

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

4223 or "user@DOMAIN" 

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

4225 Defaults to "krbtgt/<realm>" 

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

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

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

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

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

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

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

4233 'password' is the password of the p12. 

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

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

4236 

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

4238 

4239 Example:: 

4240 

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

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

4243 

4244 Equivalent:: 

4245 

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

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

4248 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

4250 

4251 Example using PKINIT with a p12:: 

4252 

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

4254 """ 

4255 if realm is None: 

4256 _, realm = _parse_upn(upn) 

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

4258 if password is None: 

4259 try: 

4260 from prompt_toolkit import prompt 

4261 

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

4263 except ImportError: 

4264 password = input("Enter password: ") 

4265 cli = KerberosClient( 

4266 mode=KerberosClient.MODE.AS_REQ, 

4267 realm=realm, 

4268 ip=ip, 

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

4270 host=host, 

4271 upn=upn, 

4272 password=password, 

4273 key=key, 

4274 p12=p12, 

4275 x509=x509, 

4276 x509key=x509key, 

4277 **kwargs, 

4278 ) 

4279 cli.run() 

4280 cli.stop() 

4281 return cli.result 

4282 

4283 

4284def krb_tgs_req( 

4285 upn, 

4286 spn, 

4287 sessionkey, 

4288 ticket, 

4289 ip=None, 

4290 renew=False, 

4291 realm=None, 

4292 additional_tickets=[], 

4293 u2u=False, 

4294 etypes=None, 

4295 for_user=None, 

4296 s4u2proxy=False, 

4297 **kwargs, 

4298): 

4299 r""" 

4300 Kerberos TGS-Req 

4301 

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

4303 or "user@DOMAIN" 

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

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

4306 :param ticket: the tgt ticket 

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

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

4309 :param renew: ask for renewal 

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

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

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

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

4314 :param etypes: array of EncryptionType values. 

4315 By default: AES128, AES256, RC4, DES_MD5 

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

4317 S4U2Self extension. 

4318 

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

4320 

4321 Example:: 

4322 

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

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

4325 

4326 Equivalent:: 

4327 

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

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

4330 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

4332 """ 

4333 cli = KerberosClient( 

4334 mode=KerberosClient.MODE.TGS_REQ, 

4335 realm=realm, 

4336 upn=upn, 

4337 ip=ip, 

4338 spn=spn, 

4339 key=sessionkey, 

4340 ticket=ticket, 

4341 renew=renew, 

4342 additional_tickets=additional_tickets, 

4343 u2u=u2u, 

4344 etypes=etypes, 

4345 for_user=for_user, 

4346 s4u2proxy=s4u2proxy, 

4347 **kwargs, 

4348 ) 

4349 cli.run() 

4350 cli.stop() 

4351 return cli.result 

4352 

4353 

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

4355 """ 

4356 Kerberos AS-Req then TGS-Req 

4357 """ 

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

4359 if not res: 

4360 return 

4361 

4362 return krb_tgs_req( 

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

4364 spn=spn, 

4365 sessionkey=res.sessionkey, 

4366 ticket=res.asrep.ticket, 

4367 ip=ip, 

4368 **kwargs, 

4369 ) 

4370 

4371 

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

4373 """ 

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

4375 """ 

4376 if realm is None: 

4377 _, realm = _parse_upn(upn) 

4378 cli = KerberosClient( 

4379 mode=KerberosClient.MODE.GET_SALT, 

4380 realm=realm, 

4381 ip=ip, 

4382 spn="krbtgt/" + realm, 

4383 upn=upn, 

4384 host=host, 

4385 **kwargs, 

4386 ) 

4387 cli.run() 

4388 cli.stop() 

4389 return cli.result 

4390 

4391 

4392def kpasswd( 

4393 upn, 

4394 targetupn=None, 

4395 ip=None, 

4396 password=None, 

4397 newpassword=None, 

4398 key=None, 

4399 ticket=None, 

4400 realm=None, 

4401 ssp=None, 

4402 setpassword=None, 

4403 timeout=3, 

4404 port=464, 

4405 debug=0, 

4406 **kwargs, 

4407): 

4408 """ 

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

4410 

4411 :param upn: the UPN to use for authentication 

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

4413 same as upn. 

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

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

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

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

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

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

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

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

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

4423 """ 

4424 from scapy.layers.ldap import dclocator 

4425 

4426 if not realm: 

4427 _, realm = _parse_upn(upn) 

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

4429 if ip is None: 

4430 ip = dclocator( 

4431 realm, 

4432 timeout=timeout, 

4433 # Use connect mode instead of ldap for compatibility 

4434 # with MIT kerberos servers 

4435 mode="connect", 

4436 port=port, 

4437 debug=debug, 

4438 ).ip 

4439 if ssp is None and ticket is not None: 

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

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

4442 if tktspn == "krbtgt": 

4443 log_runtime.info( 

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

4445 ) 

4446 setpassword = True 

4447 resp = krb_tgs_req( 

4448 upn=upn, 

4449 spn=spn, 

4450 ticket=ticket, 

4451 sessionkey=key, 

4452 ip=ip, 

4453 debug=debug, 

4454 ) 

4455 if resp is None: 

4456 return 

4457 ticket = resp.tgsrep.ticket 

4458 key = resp.sessionkey 

4459 if setpassword is None: 

4460 setpassword = bool(targetupn) 

4461 elif setpassword and targetupn is None: 

4462 targetupn = upn 

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

4464 # Get a ticket for kadmin/changepw 

4465 if ssp is None: 

4466 if ticket is None: 

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

4468 resp = krb_as_req( 

4469 upn=upn, 

4470 spn=spn, 

4471 key=key, 

4472 ip=ip, 

4473 password=password, 

4474 debug=debug, 

4475 ) 

4476 if resp is None: 

4477 return 

4478 ticket = resp.asrep.ticket 

4479 key = resp.sessionkey 

4480 ssp = KerberosSSP( 

4481 UPN=upn, 

4482 SPN=spn, 

4483 ST=ticket, 

4484 KEY=key, 

4485 DC_IP=ip, 

4486 debug=debug, 

4487 **kwargs, 

4488 ) 

4489 Context, tok, status = ssp.GSS_Init_sec_context( 

4490 None, 

4491 req_flags=0, # No GSS_C_MUTUAL_FLAG 

4492 ) 

4493 if status != GSS_S_CONTINUE_NEEDED: 

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

4495 if tok: 

4496 tok.show() 

4497 return 

4498 apreq = tok.innerToken.root 

4499 # Connect 

4500 sock = socket.socket() 

4501 sock.settimeout(timeout) 

4502 sock.connect((ip, port)) 

4503 sock = StreamSocket(sock, KpasswdTCPHeader) 

4504 # Do KPASSWD request 

4505 if newpassword is None: 

4506 try: 

4507 from prompt_toolkit import prompt 

4508 

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

4510 except ImportError: 

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

4512 krbpriv = KRB_PRIV(encPart=EncryptedData()) 

4513 krbpriv.encPart.encrypt( 

4514 Context.KrbSessionKey, 

4515 EncKrbPrivPart( 

4516 sAddress=HostAddress( 

4517 addrType=ASN1_INTEGER(2), # IPv4 

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

4519 ), 

4520 userData=ASN1_STRING( 

4521 bytes( 

4522 ChangePasswdData( 

4523 newpasswd=newpassword, 

4524 targname=PrincipalName.fromUPN(targetupn), 

4525 targrealm=realm, 

4526 ) 

4527 ) 

4528 if setpassword 

4529 else newpassword 

4530 ), 

4531 timestamp=None, 

4532 usec=None, 

4533 seqNumber=Context.SendSeqNum, 

4534 ), 

4535 ) 

4536 resp = sock.sr1( 

4537 KpasswdTCPHeader() 

4538 / KPASSWD_REQ( 

4539 pvno=0xFF80 if setpassword else 1, 

4540 apreq=apreq, 

4541 krbpriv=krbpriv, 

4542 ), 

4543 timeout=timeout, 

4544 verbose=0, 

4545 ) 

4546 # Verify KPASSWD response 

4547 if not resp: 

4548 raise TimeoutError("KPASSWD_REQ timed out !") 

4549 if KPASSWD_REP not in resp: 

4550 resp.show() 

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

4552 Context, tok, status = ssp.GSS_Init_sec_context( 

4553 Context, 

4554 input_token=resp.aprep, 

4555 ) 

4556 if status != GSS_S_COMPLETE: 

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

4558 if tok: 

4559 tok.show() 

4560 return 

4561 # Parse answer KRB_PRIV 

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

4563 userRep = KPasswdRepData(krbanswer.userData.val) 

4564 if userRep.resultCode != 0: 

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

4566 userRep.show() 

4567 return 

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

4569 

4570 

4571# SSP 

4572 

4573 

4574class KerberosSSP(SSP): 

4575 """ 

4576 The KerberosSSP 

4577 

4578 Client settings: 

4579 

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

4581 If not provided, will be retrieved 

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

4583 target_name provided in the GSS_Init_sec_context 

4584 :param UPN: The client UPN 

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

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

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

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

4589 OR the session key associated with the TGT 

4590 OR the kerberos key associated with the UPN 

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

4592 password of the UPN. 

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

4594 

4595 Server settings: 

4596 

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

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

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

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

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

4602 this IP using using the KEY when using U2U. 

4603 """ 

4604 

4605 auth_type = 0x10 

4606 

4607 class STATE(SSP.STATE): 

4608 INIT = 1 

4609 CLI_SENT_TGTREQ = 2 

4610 CLI_SENT_APREQ = 3 

4611 CLI_RCVD_APREP = 4 

4612 SRV_SENT_APREP = 5 

4613 FAILED = -1 

4614 

4615 class CONTEXT(SSP.CONTEXT): 

4616 __slots__ = [ 

4617 "SessionKey", 

4618 "ServerHostname", 

4619 "U2U", 

4620 "KrbSessionKey", # raw Key object 

4621 "ST", # the service ticket 

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

4623 "SeqNum", # for AP 

4624 "SendSeqNum", # for MIC 

4625 "RecvSeqNum", # for MIC 

4626 "IsAcceptor", 

4627 "SendSealKeyUsage", 

4628 "SendSignKeyUsage", 

4629 "RecvSealKeyUsage", 

4630 "RecvSignKeyUsage", 

4631 # server-only 

4632 "UPN", 

4633 "PAC", 

4634 ] 

4635 

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

4637 self.state = KerberosSSP.STATE.INIT 

4638 self.SessionKey = None 

4639 self.ServerHostname = None 

4640 self.U2U = False 

4641 self.SendSeqNum = 0 

4642 self.RecvSeqNum = 0 

4643 self.KrbSessionKey = None 

4644 self.ST = None 

4645 self.STSessionKey = None 

4646 self.IsAcceptor = IsAcceptor 

4647 self.UPN = None 

4648 self.PAC = None 

4649 # [RFC 4121] sect 2 

4650 if IsAcceptor: 

4651 self.SendSealKeyUsage = 22 

4652 self.SendSignKeyUsage = 23 

4653 self.RecvSealKeyUsage = 24 

4654 self.RecvSignKeyUsage = 25 

4655 else: 

4656 self.SendSealKeyUsage = 24 

4657 self.SendSignKeyUsage = 25 

4658 self.RecvSealKeyUsage = 22 

4659 self.RecvSignKeyUsage = 23 

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

4661 

4662 def clifailure(self): 

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

4664 

4665 def __repr__(self): 

4666 if self.U2U: 

4667 return "KerberosSSP-U2U" 

4668 return "KerberosSSP" 

4669 

4670 def __init__( 

4671 self, 

4672 ST=None, 

4673 UPN=None, 

4674 PASSWORD=None, 

4675 U2U=False, 

4676 KEY=None, 

4677 SPN=None, 

4678 TGT=None, 

4679 DC_IP=None, 

4680 SKEY_TYPE=None, 

4681 debug=0, 

4682 **kwargs, 

4683 ): 

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

4685 

4686 self.ST = ST 

4687 self.UPN = UPN 

4688 self.KEY = KEY 

4689 self.SPN = SPN 

4690 self.TGT = TGT 

4691 self.TGTSessionKey = None 

4692 self.PASSWORD = PASSWORD 

4693 self.U2U = U2U 

4694 self.DC_IP = DC_IP 

4695 self.debug = debug 

4696 if SKEY_TYPE is None: 

4697 SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96 

4698 self.SKEY_TYPE = SKEY_TYPE 

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

4700 

4701 def GSS_Inquire_names_for_mech(self): 

4702 mechs = [ 

4703 "1.2.840.48018.1.2.2", # MS KRB5 - Microsoft Kerberos 5 

4704 "1.2.840.113554.1.2.2", # Kerberos 5 

4705 ] 

4706 if self.U2U: 

4707 mechs.append("1.2.840.113554.1.2.2.3") # Kerberos 5 - User to User 

4708 return mechs 

4709 

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

4711 """ 

4712 [MS-KILE] sect 3.4.5.6 

4713 

4714 - AES: RFC4121 sect 4.2.6.1 

4715 """ 

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

4717 # Concatenate the ToSign 

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

4719 sig = KRB_InnerToken( 

4720 TOK_ID=b"\x04\x04", 

4721 root=KRB_GSS_MIC( 

4722 Flags="AcceptorSubkey" 

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

4724 SND_SEQ=Context.SendSeqNum, 

4725 ), 

4726 ) 

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

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

4729 keyusage=Context.SendSignKeyUsage, 

4730 text=ToSign, 

4731 ) 

4732 else: 

4733 raise NotImplementedError 

4734 Context.SendSeqNum += 1 

4735 return sig 

4736 

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

4738 """ 

4739 [MS-KILE] sect 3.4.5.7 

4740 

4741 - AES: RFC4121 sect 4.2.6.1 

4742 """ 

4743 Context.RecvSeqNum = signature.root.SND_SEQ 

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

4745 # Concatenate the ToSign 

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

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

4748 sig = Context.KrbSessionKey.make_checksum( 

4749 keyusage=Context.RecvSignKeyUsage, 

4750 text=ToSign, 

4751 ) 

4752 else: 

4753 raise NotImplementedError 

4754 if sig != signature.root.SGN_CKSUM: 

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

4756 

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

4758 """ 

4759 [MS-KILE] sect 3.4.5.4 

4760 

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

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

4763 """ 

4764 # Is confidentiality in use? 

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

4766 x.conf_req_flag for x in msgs 

4767 ) 

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

4769 # Build token 

4770 tok = KRB_InnerToken( 

4771 TOK_ID=b"\x05\x04", 

4772 root=KRB_GSS_Wrap( 

4773 Flags="AcceptorSubkey" 

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

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

4776 SND_SEQ=Context.SendSeqNum, 

4777 RRC=0, 

4778 ), 

4779 ) 

4780 Context.SendSeqNum += 1 

4781 # Real separation starts now: RFC4121 sect 4.2.4 

4782 if confidentiality: 

4783 # Confidentiality is requested (see RFC4121 sect 4.3) 

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

4785 # 0. Roll confounder 

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

4787 # 1. Concatenate the data to be encrypted 

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

4789 DataLen = len(Data) 

4790 # 2. Add filler 

4791 if qop_req & GSS_QOP_REQ_FLAGS.GSS_S_NO_SECBUFFER_PADDING: 

4792 # Special case for compatibility with Windows API. See 

4793 # GSS_QOP_REQ_FLAGS. 

4794 tok.root.EC = 0 

4795 else: 

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

4797 # be zero" 

4798 tok.root.EC = ( 

4799 (-DataLen) % Context.KrbSessionKey.ep.blocksize 

4800 ) or 16 

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

4802 Data += Filler 

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

4804 PlainHeader = bytes(tok)[:16] 

4805 Data += PlainHeader 

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

4807 ToSign = Confounder 

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

4809 ToSign += Filler 

4810 ToSign += PlainHeader 

4811 # 5. Finalize token for signing 

4812 # "The RRC field is [...] 28 if encryption is requested." 

4813 tok.root.RRC = 28 

4814 # 6. encrypt() is the encryption operation (which provides for 

4815 # integrity protection) 

4816 Data = Context.KrbSessionKey.encrypt( 

4817 keyusage=Context.SendSealKeyUsage, 

4818 plaintext=Data, 

4819 confounder=Confounder, 

4820 signtext=ToSign, 

4821 ) 

4822 # 7. Rotate 

4823 Data = strrot(Data, tok.root.RRC + tok.root.EC) 

4824 # 8. Split (token and encrypted messages) 

4825 toklen = len(Data) - DataLen 

4826 tok.root.Data = Data[:toklen] 

4827 offset = toklen 

4828 for msg in msgs: 

4829 msglen = len(msg.data) 

4830 if msg.conf_req_flag: 

4831 msg.data = Data[offset : offset + msglen] 

4832 offset += msglen 

4833 return msgs, tok 

4834 else: 

4835 # No confidentiality is requested 

4836 # {"header" | plaintext-data | get_mic(plaintext-data | "header")} 

4837 # 0. Concatenate the data 

4838 Data = b"".join(x.data for x in msgs if x.sign) 

4839 DataLen = len(Data) 

4840 # 1. Add first 16 octets of the Wrap token "header" 

4841 ToSign = Data 

4842 ToSign += bytes(tok)[:16] 

4843 # 2. get_mic() is the checksum operation for the required 

4844 # checksum mechanism 

4845 Mic = Context.KrbSessionKey.make_checksum( 

4846 keyusage=Context.SendSealKeyUsage, 

4847 text=ToSign, 

4848 ) 

4849 # In Wrap tokens without confidentiality, the EC field SHALL be used 

4850 # to encode the number of octets in the trailing checksum 

4851 tok.root.EC = 12 # len(tok.root.Data) == 12 for AES 

4852 # "The RRC field ([RFC4121] section 4.2.5) is 12 if no encryption 

4853 # is requested" 

4854 tok.root.RRC = 12 

4855 # 3. Concat and pack 

4856 for msg in msgs: 

4857 if msg.sign: 

4858 msg.data = b"" 

4859 Data = Data + Mic 

4860 # 4. Rotate 

4861 tok.root.Data = strrot(Data, tok.root.RRC) 

4862 return msgs, tok 

4863 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

4864 # Build token 

4865 seq = struct.pack(">I", Context.SendSeqNum) 

4866 tok = KRB_InnerToken( 

4867 TOK_ID=b"\x02\x01", 

4868 root=KRB_GSS_Wrap_RFC1964( 

4869 SGN_ALG="HMAC", 

4870 SEAL_ALG="RC4" if confidentiality else "none", 

4871 SND_SEQ=seq 

4872 + ( 

4873 # See errata 

4874 b"\xff\xff\xff\xff" 

4875 if Context.IsAcceptor 

4876 else b"\x00\x00\x00\x00" 

4877 ), 

4878 ), 

4879 ) 

4880 Context.SendSeqNum += 1 

4881 # 0. Concatenate data 

4882 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

4883 ToEncrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

4884 Kss = Context.KrbSessionKey.key 

4885 # 1. Roll confounder 

4886 Confounder = os.urandom(8) 

4887 # 2. Compute the 'Kseq' key 

4888 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

4889 if Context.KrbSessionKey.etype == 24: # EXP 

4890 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4891 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

4892 else: 

4893 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

4894 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

4895 # 3. Build SGN_CKSUM 

4896 tok.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

4897 keyusage=13, # See errata 

4898 text=bytes(tok)[:8] + Confounder + ToSign, 

4899 )[:8] 

4900 # 4. Populate token + encrypt 

4901 if confidentiality: 

4902 # 'encrypt' is requested 

4903 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

4904 tok.root.CONFOUNDER = rc4.update(Confounder) 

4905 Data = rc4.update(ToEncrypt) 

4906 # Split encrypted data 

4907 offset = 0 

4908 for msg in msgs: 

4909 msglen = len(msg.data) 

4910 if msg.conf_req_flag: 

4911 msg.data = Data[offset : offset + msglen] 

4912 offset += msglen 

4913 else: 

4914 # 'encrypt' is not requested 

4915 tok.root.CONFOUNDER = Confounder 

4916 # 5. Compute the 'Kseq' key 

4917 if Context.KrbSessionKey.etype == 24: # EXP 

4918 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

4919 Kseq = Kseq[:7] + b"\xab" * 9 

4920 else: 

4921 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

4922 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

4923 # 6. Encrypt 'SND_SEQ' 

4924 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

4925 tok.root.SND_SEQ = rc4.update(tok.root.SND_SEQ) 

4926 # 7. Include 'InitialContextToken pseudo ASN.1 header' 

4927 tok = KRB_GSSAPI_Token( 

4928 MechType="1.2.840.113554.1.2.2", # Kerberos 5 

4929 innerToken=tok, 

4930 ) 

4931 return msgs, tok 

4932 else: 

4933 raise NotImplementedError 

4934 

4935 def GSS_UnwrapEx(self, Context, msgs, signature): 

4936 """ 

4937 [MS-KILE] sect 3.4.5.5 

4938 

4939 - AES: RFC4121 sect 4.2.6.2 

4940 - HMAC-RC4: RFC4757 sect 7.3 

4941 """ 

4942 if Context.KrbSessionKey.etype in [17, 18]: # AES 

4943 confidentiality = signature.root.Flags.Sealed 

4944 # Real separation starts now: RFC4121 sect 4.2.4 

4945 if confidentiality: 

4946 # 0. Concatenate the data 

4947 Data = signature.root.Data 

4948 Data += b"".join(x.data for x in msgs if x.conf_req_flag) 

4949 # 1. Un-Rotate 

4950 Data = strrot(Data, signature.root.RRC + signature.root.EC, right=False) 

4951 

4952 # 2. Function to build 'ToSign', exclusively used for checksum 

4953 def MakeToSign(Confounder, DecText): 

4954 offset = 0 

4955 # 2.a Confounder 

4956 ToSign = Confounder 

4957 # 2.b Messages 

4958 for msg in msgs: 

4959 msglen = len(msg.data) 

4960 if msg.conf_req_flag: 

4961 ToSign += DecText[offset : offset + msglen] 

4962 offset += msglen 

4963 elif msg.sign: 

4964 ToSign += msg.data 

4965 # 2.c Filler & Padding 

4966 ToSign += DecText[offset:] 

4967 return ToSign 

4968 

4969 # 3. Decrypt 

4970 Data = Context.KrbSessionKey.decrypt( 

4971 keyusage=Context.RecvSealKeyUsage, 

4972 ciphertext=Data, 

4973 presignfunc=MakeToSign, 

4974 ) 

4975 # 4. Split 

4976 Data, f16header = ( 

4977 Data[:-16], 

4978 Data[-16:], 

4979 ) 

4980 # 5. Check header 

4981 hdr = signature.copy() 

4982 hdr.root.RRC = 0 

4983 if f16header != bytes(hdr)[:16]: 

4984 raise ValueError("ERROR: Headers don't match") 

4985 # 6. Split (and ignore filler) 

4986 offset = 0 

4987 for msg in msgs: 

4988 msglen = len(msg.data) 

4989 if msg.conf_req_flag: 

4990 msg.data = Data[offset : offset + msglen] 

4991 offset += msglen 

4992 # Case without msgs 

4993 if len(msgs) == 1 and not msgs[0].data: 

4994 msgs[0].data = Data 

4995 return msgs 

4996 else: 

4997 # No confidentiality is requested 

4998 # 0. Concatenate the data 

4999 Data = signature.root.Data 

5000 Data += b"".join(x.data for x in msgs if x.sign) 

5001 # 1. Un-Rotate 

5002 Data = strrot(Data, signature.root.RRC, right=False) 

5003 # 2. Split 

5004 Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :] 

5005 # "Both the EC field and the RRC field in 

5006 # the token header SHALL be filled with zeroes for the purpose of 

5007 # calculating the checksum." 

5008 ToSign = Data 

5009 hdr = signature.copy() 

5010 hdr.root.RRC = 0 

5011 hdr.root.EC = 0 

5012 # Concatenate the data 

5013 ToSign += bytes(hdr)[:16] 

5014 # 3. Calculate the signature 

5015 sig = Context.KrbSessionKey.make_checksum( 

5016 keyusage=Context.RecvSealKeyUsage, 

5017 text=ToSign, 

5018 ) 

5019 # 4. Compare 

5020 if sig != Mic: 

5021 raise ValueError("ERROR: Checksums don't match") 

5022 # Case without msgs 

5023 if len(msgs) == 1 and not msgs[0].data: 

5024 msgs[0].data = Data 

5025 return msgs 

5026 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

5027 # Drop wrapping 

5028 tok = signature.innerToken 

5029 

5030 # Detect confidentiality 

5031 confidentiality = tok.root.SEAL_ALG != 0xFFFF 

5032 

5033 # 0. Concatenate data 

5034 ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

5035 Kss = Context.KrbSessionKey.key 

5036 # 1. Compute the 'Kseq' key 

5037 if Context.KrbSessionKey.etype == 24: # EXP 

5038 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5039 Kseq = Kseq[:7] + b"\xab" * 9 

5040 else: 

5041 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

5042 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

5043 # 2. Decrypt 'SND_SEQ' 

5044 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

5045 seq = rc4.update(tok.root.SND_SEQ)[:4] 

5046 # 3. Compute the 'Kcrypt' key 

5047 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

5048 if Context.KrbSessionKey.etype == 24: # EXP 

5049 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5050 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

5051 else: 

5052 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

5053 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

5054 # 4. Decrypt 

5055 if confidentiality: 

5056 # 'encrypt' was requested 

5057 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

5058 Confounder = rc4.update(tok.root.CONFOUNDER) 

5059 Data = rc4.update(ToDecrypt) 

5060 # Split encrypted data 

5061 offset = 0 

5062 for msg in msgs: 

5063 msglen = len(msg.data) 

5064 if msg.conf_req_flag: 

5065 msg.data = Data[offset : offset + msglen] 

5066 offset += msglen 

5067 else: 

5068 # 'encrypt' was not requested 

5069 Confounder = tok.root.CONFOUNDER 

5070 # 5. Verify SGN_CKSUM 

5071 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

5072 Context.KrbSessionKey.verify_checksum( 

5073 keyusage=13, # See errata 

5074 text=bytes(tok)[:8] + Confounder + ToSign, 

5075 cksum=tok.root.SGN_CKSUM, 

5076 ) 

5077 return msgs 

5078 else: 

5079 raise NotImplementedError 

5080 

5081 def GSS_Init_sec_context( 

5082 self, 

5083 Context: CONTEXT, 

5084 input_token=None, 

5085 target_name: Optional[str] = None, 

5086 req_flags: Optional[GSS_C_FLAGS] = None, 

5087 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5088 ): 

5089 if Context is None: 

5090 # New context 

5091 Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags) 

5092 

5093 if Context.state == self.STATE.INIT and self.U2U: 

5094 # U2U - Get TGT 

5095 Context.state = self.STATE.CLI_SENT_TGTREQ 

5096 return ( 

5097 Context, 

5098 KRB_GSSAPI_Token( 

5099 MechType="1.2.840.113554.1.2.2.3", # U2U 

5100 innerToken=KRB_InnerToken( 

5101 TOK_ID=b"\x04\x00", 

5102 root=KRB_TGT_REQ(), 

5103 ), 

5104 ), 

5105 GSS_S_CONTINUE_NEEDED, 

5106 ) 

5107 

5108 if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]: 

5109 if not self.UPN: 

5110 raise ValueError("Missing UPN attribute") 

5111 

5112 # Do we have a ST? 

5113 if self.ST is None: 

5114 # Client sends an AP-req 

5115 if not self.SPN and not target_name: 

5116 raise ValueError("Missing SPN/target_name attribute") 

5117 additional_tickets = [] 

5118 

5119 if self.U2U: 

5120 try: 

5121 # GSSAPI / Kerberos 

5122 tgt_rep = input_token.root.innerToken.root 

5123 except AttributeError: 

5124 try: 

5125 # Kerberos 

5126 tgt_rep = input_token.innerToken.root 

5127 except AttributeError: 

5128 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5129 if not isinstance(tgt_rep, KRB_TGT_REP): 

5130 tgt_rep.show() 

5131 raise ValueError("KerberosSSP: Unexpected input_token !") 

5132 additional_tickets = [tgt_rep.ticket] 

5133 

5134 if self.TGT is None: 

5135 # Get TGT. We were passed a kerberos key 

5136 res = krb_as_req( 

5137 upn=self.UPN, 

5138 ip=self.DC_IP, 

5139 key=self.KEY, 

5140 password=self.PASSWORD, 

5141 debug=self.debug, 

5142 verbose=bool(self.debug), 

5143 ) 

5144 if res is None: 

5145 # Failed to retrieve the ticket 

5146 return Context, None, GSS_S_FAILURE 

5147 

5148 # Update UPN (could have been canonicalized) 

5149 self.UPN = res.upn 

5150 

5151 # Store TGT, 

5152 self.TGT = res.asrep.ticket 

5153 self.TGTSessionKey = res.sessionkey 

5154 elif self.TGTSessionKey is None: 

5155 # We have a TGT and were passed its key 

5156 self.TGTSessionKey = self.KEY 

5157 

5158 # Get ST 

5159 if not self.TGTSessionKey: 

5160 raise ValueError("Cannot use TGT without the KEY") 

5161 

5162 res = krb_tgs_req( 

5163 upn=self.UPN, 

5164 spn=self.SPN or target_name, 

5165 ip=self.DC_IP, 

5166 sessionkey=self.TGTSessionKey, 

5167 ticket=self.TGT, 

5168 additional_tickets=additional_tickets, 

5169 u2u=self.U2U, 

5170 debug=self.debug, 

5171 verbose=bool(self.debug), 

5172 ) 

5173 if not res: 

5174 # Failed to retrieve the ticket 

5175 return Context, None, GSS_S_FAILURE 

5176 

5177 # Store the service ticket and associated key 

5178 Context.ST, Context.STSessionKey = res.tgsrep.ticket, res.sessionkey 

5179 elif not self.KEY: 

5180 raise ValueError("Must provide KEY with ST") 

5181 else: 

5182 # We were passed a ST and its key 

5183 Context.ST = self.ST 

5184 Context.STSessionKey = self.KEY 

5185 

5186 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5187 raise ValueError( 

5188 "Cannot use GSS_C_DELEG_FLAG when passed a service ticket !" 

5189 ) 

5190 

5191 # Save ServerHostname 

5192 if len(Context.ST.sname.nameString) == 2: 

5193 Context.ServerHostname = Context.ST.sname.nameString[1].val.decode() 

5194 

5195 # Build the KRB-AP 

5196 apOptions = ASN1_BIT_STRING("000") 

5197 if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG: 

5198 apOptions.set(2, "1") # mutual-required 

5199 if self.U2U: 

5200 apOptions.set(1, "1") # use-session-key 

5201 Context.U2U = True 

5202 ap_req = KRB_AP_REQ( 

5203 apOptions=apOptions, 

5204 ticket=Context.ST, 

5205 authenticator=EncryptedData(), 

5206 ) 

5207 

5208 # Get the current time 

5209 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5210 # Pick a random session key 

5211 Context.KrbSessionKey = Key.new_random_key( 

5212 self.SKEY_TYPE, 

5213 ) 

5214 

5215 # We use a random SendSeqNum 

5216 Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix() 

5217 

5218 # Get the realm of the client 

5219 _, crealm = _parse_upn(self.UPN) 

5220 

5221 # Build the RFC4121 authenticator checksum 

5222 authenticator_checksum = KRB_AuthenticatorChecksum( 

5223 # RFC 4121 sect 4.1.1.2 

5224 # "The Bnd field contains the MD5 hash of channel bindings" 

5225 Bnd=( 

5226 chan_bindings.digestMD5() 

5227 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5228 else (b"\x00" * 16) 

5229 ), 

5230 Flags=int(Context.flags), 

5231 ) 

5232 

5233 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5234 # Delegate TGT 

5235 raise NotImplementedError("GSS_C_DELEG_FLAG is not implemented !") 

5236 # authenticator_checksum.Deleg = KRB_CRED( 

5237 # tickets=[self.TGT], 

5238 # encPart=EncryptedData() 

5239 # ) 

5240 # authenticator_checksum.encPart.encrypt( 

5241 # Context.STSessionKey, 

5242 # EncKrbCredPart( 

5243 # ticketInfo=KrbCredInfo( 

5244 # key=EncryptionKey.fromKey(self.TGTSessionKey), 

5245 # prealm=ASN1_GENERAL_STRING(crealm), 

5246 # pname=PrincipalName.fromUPN(self.UPN), 

5247 # # TODO: rework API to pass starttime... here. 

5248 # sreralm=self.TGT.realm, 

5249 # sname=self.TGT.sname, 

5250 # ) 

5251 # ) 

5252 # ) 

5253 

5254 # Build and encrypt the full KRB_Authenticator 

5255 ap_req.authenticator.encrypt( 

5256 Context.STSessionKey, 

5257 KRB_Authenticator( 

5258 crealm=crealm, 

5259 cname=PrincipalName.fromUPN(self.UPN), 

5260 cksum=Checksum( 

5261 cksumtype="KRB-AUTHENTICATOR", checksum=authenticator_checksum 

5262 ), 

5263 ctime=ASN1_GENERALIZED_TIME(now_time), 

5264 cusec=ASN1_INTEGER(0), 

5265 subkey=EncryptionKey.fromKey(Context.KrbSessionKey), 

5266 seqNumber=Context.SendSeqNum, 

5267 encAuthorizationData=AuthorizationData( 

5268 seq=[ 

5269 AuthorizationDataItem( 

5270 adType="AD-IF-RELEVANT", 

5271 adData=AuthorizationData( 

5272 seq=[ 

5273 AuthorizationDataItem( 

5274 adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

5275 adData=KERB_AD_RESTRICTION_ENTRY( 

5276 restriction=LSAP_TOKEN_INFO_INTEGRITY( 

5277 MachineID=bytes(RandBin(32)), 

5278 PermanentMachineID=bytes( 

5279 RandBin(32) 

5280 ), 

5281 ) 

5282 ), 

5283 ), 

5284 # This isn't documented, but sent on Windows :/ 

5285 AuthorizationDataItem( 

5286 adType="KERB-LOCAL", 

5287 adData=b"\x00" * 16, 

5288 ), 

5289 ] 

5290 + ( 

5291 # Channel bindings 

5292 [ 

5293 AuthorizationDataItem( 

5294 adType="AD-AUTH-DATA-AP-OPTIONS", 

5295 adData=KERB_AUTH_DATA_AP_OPTIONS( 

5296 apOptions="KERB_AP_OPTIONS_CBT" 

5297 ), 

5298 ) 

5299 ] 

5300 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5301 else [] 

5302 ) 

5303 ), 

5304 ) 

5305 ] 

5306 ), 

5307 ), 

5308 ) 

5309 Context.state = self.STATE.CLI_SENT_APREQ 

5310 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5311 # Raw kerberos DCE-STYLE 

5312 return Context, ap_req, GSS_S_CONTINUE_NEEDED 

5313 else: 

5314 # Kerberos wrapper 

5315 return ( 

5316 Context, 

5317 KRB_GSSAPI_Token( 

5318 innerToken=KRB_InnerToken( 

5319 root=ap_req, 

5320 ) 

5321 ), 

5322 GSS_S_CONTINUE_NEEDED, 

5323 ) 

5324 

5325 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5326 if isinstance(input_token, KRB_AP_REP): 

5327 # Raw AP_REP was passed 

5328 ap_rep = input_token 

5329 else: 

5330 try: 

5331 # GSSAPI / Kerberos 

5332 ap_rep = input_token.root.innerToken.root 

5333 except AttributeError: 

5334 try: 

5335 # Kerberos 

5336 ap_rep = input_token.innerToken.root 

5337 except AttributeError: 

5338 try: 

5339 # Raw kerberos DCE-STYLE 

5340 ap_rep = input_token.root 

5341 except AttributeError: 

5342 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5343 if not isinstance(ap_rep, KRB_AP_REP): 

5344 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5345 

5346 # Retrieve SessionKey 

5347 repPart = ap_rep.encPart.decrypt(Context.STSessionKey) 

5348 if repPart.subkey is not None: 

5349 Context.SessionKey = repPart.subkey.keyvalue.val 

5350 Context.KrbSessionKey = repPart.subkey.toKey() 

5351 

5352 # OK ! 

5353 Context.state = self.STATE.CLI_RCVD_APREP 

5354 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5355 # [MS-KILE] sect 3.4.5.1 

5356 # The client MUST generate an additional AP exchange reply message 

5357 # exactly as the server would as the final message to send to the 

5358 # server. 

5359 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5360 cli_ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5361 cli_ap_rep.encPart.encrypt( 

5362 Context.STSessionKey, 

5363 EncAPRepPart( 

5364 ctime=ASN1_GENERALIZED_TIME(now_time), 

5365 seqNumber=repPart.seqNumber, 

5366 subkey=None, 

5367 ), 

5368 ) 

5369 return Context, cli_ap_rep, GSS_S_COMPLETE 

5370 return Context, None, GSS_S_COMPLETE 

5371 elif ( 

5372 Context.state == self.STATE.CLI_RCVD_APREP 

5373 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5374 ): 

5375 # DCE_STYLE with SPNEGOSSP 

5376 return Context, None, GSS_S_COMPLETE 

5377 else: 

5378 raise ValueError("KerberosSSP: Unknown state") 

5379 

5380 def GSS_Accept_sec_context( 

5381 self, 

5382 Context: CONTEXT, 

5383 input_token=None, 

5384 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5385 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5386 ): 

5387 if Context is None: 

5388 # New context 

5389 Context = self.CONTEXT(IsAcceptor=True, req_flags=req_flags) 

5390 

5391 import scapy.layers.msrpce.mspac # noqa: F401 

5392 

5393 if Context.state == self.STATE.INIT: 

5394 if self.UPN and self.SPN: 

5395 raise ValueError("Cannot use SPN and UPN at the same time !") 

5396 if self.SPN and self.TGT: 

5397 raise ValueError("Cannot use TGT with SPN.") 

5398 if self.UPN and not self.TGT: 

5399 # UPN is provided: use U2U 

5400 res = krb_as_req( 

5401 self.UPN, 

5402 self.DC_IP, 

5403 key=self.KEY, 

5404 password=self.PASSWORD, 

5405 ) 

5406 self.TGT, self.TGTSessionKey = res.asrep.ticket, res.sessionkey 

5407 

5408 # Server receives AP-req, sends AP-rep 

5409 if isinstance(input_token, KRB_AP_REQ): 

5410 # Raw AP_REQ was passed 

5411 ap_req = input_token 

5412 else: 

5413 try: 

5414 # GSSAPI/Kerberos 

5415 ap_req = input_token.root.innerToken.root 

5416 except AttributeError: 

5417 try: 

5418 # Kerberos 

5419 ap_req = input_token.innerToken.root 

5420 except AttributeError: 

5421 try: 

5422 # Raw kerberos 

5423 ap_req = input_token.root 

5424 except AttributeError: 

5425 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5426 

5427 if isinstance(ap_req, KRB_TGT_REQ): 

5428 # Special U2U case 

5429 Context.U2U = True 

5430 return ( 

5431 None, 

5432 KRB_GSSAPI_Token( 

5433 MechType="1.2.840.113554.1.2.2.3", # U2U 

5434 innerToken=KRB_InnerToken( 

5435 TOK_ID=b"\x04\x01", 

5436 root=KRB_TGT_REP( 

5437 ticket=self.TGT, 

5438 ), 

5439 ), 

5440 ), 

5441 GSS_S_CONTINUE_NEEDED, 

5442 ) 

5443 elif not isinstance(ap_req, KRB_AP_REQ): 

5444 ap_req.show() 

5445 raise ValueError("Unexpected type in KerberosSSP") 

5446 if not self.KEY: 

5447 raise ValueError("Missing KEY attribute") 

5448 

5449 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5450 

5451 # If using a UPN, require U2U 

5452 if self.UPN and ap_req.apOptions.val[1] != "1": # use-session-key 

5453 # Required but not provided. Return an error 

5454 Context.U2U = True 

5455 err = KRB_GSSAPI_Token( 

5456 innerToken=KRB_InnerToken( 

5457 TOK_ID=b"\x03\x00", 

5458 root=KRB_ERROR( 

5459 errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED", 

5460 stime=ASN1_GENERALIZED_TIME(now_time), 

5461 realm=ap_req.ticket.realm, 

5462 sname=ap_req.ticket.sname, 

5463 eData=KRB_TGT_REP( 

5464 ticket=self.TGT, 

5465 ), 

5466 ), 

5467 ) 

5468 ) 

5469 return Context, err, GSS_S_CONTINUE_NEEDED 

5470 

5471 # Validate the 'serverName' of the ticket. 

5472 sname = ap_req.ticket.getSPN() 

5473 our_sname = self.SPN or self.UPN 

5474 if not _spn_are_equal(our_sname, sname): 

5475 warning("KerberosSSP: bad server name: %s != %s" % (sname, our_sname)) 

5476 err = KRB_GSSAPI_Token( 

5477 innerToken=KRB_InnerToken( 

5478 TOK_ID=b"\x03\x00", 

5479 root=KRB_ERROR( 

5480 errorCode="KRB_AP_ERR_BADMATCH", 

5481 stime=ASN1_GENERALIZED_TIME(now_time), 

5482 realm=ap_req.ticket.realm, 

5483 sname=ap_req.ticket.sname, 

5484 eData=None, 

5485 ), 

5486 ) 

5487 ) 

5488 return Context, err, GSS_S_BAD_MECH 

5489 

5490 # Decrypt the ticket 

5491 try: 

5492 tkt = ap_req.ticket.encPart.decrypt(self.KEY) 

5493 except ValueError as ex: 

5494 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5495 err = KRB_GSSAPI_Token( 

5496 innerToken=KRB_InnerToken( 

5497 TOK_ID=b"\x03\x00", 

5498 root=KRB_ERROR( 

5499 errorCode="KRB_AP_ERR_MODIFIED", 

5500 stime=ASN1_GENERALIZED_TIME(now_time), 

5501 realm=ap_req.ticket.realm, 

5502 sname=ap_req.ticket.sname, 

5503 eData=None, 

5504 ), 

5505 ) 

5506 ) 

5507 return Context, err, GSS_S_DEFECTIVE_CREDENTIAL 

5508 

5509 # Store information about the user in the Context 

5510 if tkt.authorizationData and tkt.authorizationData.seq: 

5511 # Get AD-IF-RELEVANT 

5512 adIfRelevant = tkt.authorizationData.getAuthData(0x1) 

5513 if adIfRelevant: 

5514 # Get AD-WIN2K-PAC 

5515 Context.PAC = adIfRelevant.getAuthData(0x80) 

5516 

5517 # Get AP-REQ session key 

5518 Context.STSessionKey = tkt.key.toKey() 

5519 authenticator = ap_req.authenticator.decrypt(Context.STSessionKey) 

5520 

5521 # Compute an application session key ([MS-KILE] sect 3.1.1.2) 

5522 subkey = None 

5523 if ap_req.apOptions.val[2] == "1": # mutual-required 

5524 appkey = Key.new_random_key( 

5525 self.SKEY_TYPE, 

5526 ) 

5527 Context.KrbSessionKey = appkey 

5528 Context.SessionKey = appkey.key 

5529 subkey = EncryptionKey.fromKey(appkey) 

5530 else: 

5531 Context.KrbSessionKey = self.KEY 

5532 Context.SessionKey = self.KEY.key 

5533 

5534 # Eventually process the "checksum" 

5535 if authenticator.cksum and authenticator.cksum.cksumtype == 0x8003: 

5536 # KRB-Authenticator 

5537 authcksum = authenticator.cksum.checksum 

5538 Context.flags = authcksum.Flags 

5539 # Check channel bindings 

5540 if ( 

5541 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5542 and chan_bindings.digestMD5() != authcksum.Bnd 

5543 and not ( 

5544 GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS in req_flags 

5545 and authcksum.Bnd == GSS_C_NO_CHANNEL_BINDINGS 

5546 ) 

5547 ): 

5548 # Channel binding checks failed. 

5549 return Context, None, GSS_S_BAD_BINDINGS 

5550 elif ( 

5551 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5552 and GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS not in req_flags 

5553 ): 

5554 # Uhoh, we required channel bindings 

5555 return Context, None, GSS_S_BAD_BINDINGS 

5556 

5557 # Build response (RFC4120 sect 3.2.4) 

5558 ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5559 ap_rep.encPart.encrypt( 

5560 Context.STSessionKey, 

5561 EncAPRepPart( 

5562 ctime=authenticator.ctime, 

5563 cusec=authenticator.cusec, 

5564 seqNumber=None, 

5565 subkey=subkey, 

5566 ), 

5567 ) 

5568 Context.state = self.STATE.SRV_SENT_APREP 

5569 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5570 # [MS-KILE] sect 3.4.5.1 

5571 return Context, ap_rep, GSS_S_CONTINUE_NEEDED 

5572 return Context, ap_rep, GSS_S_COMPLETE # success 

5573 elif ( 

5574 Context.state == self.STATE.SRV_SENT_APREP 

5575 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5576 ): 

5577 # [MS-KILE] sect 3.4.5.1 

5578 # The server MUST receive the additional AP exchange reply message and 

5579 # verify that the message is constructed correctly. 

5580 if not input_token: 

5581 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5582 # Server receives AP-req, sends AP-rep 

5583 if isinstance(input_token, KRB_AP_REP): 

5584 # Raw AP_REP was passed 

5585 ap_rep = input_token 

5586 else: 

5587 try: 

5588 # GSSAPI/Kerberos 

5589 ap_rep = input_token.root.innerToken.root 

5590 except AttributeError: 

5591 try: 

5592 # Raw Kerberos 

5593 ap_rep = input_token.root 

5594 except AttributeError: 

5595 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5596 # Decrypt the AP-REP 

5597 try: 

5598 ap_rep.encPart.decrypt(Context.STSessionKey) 

5599 except ValueError as ex: 

5600 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5601 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5602 return Context, None, GSS_S_COMPLETE # success 

5603 else: 

5604 raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state)) 

5605 

5606 def GSS_Passive( 

5607 self, 

5608 Context: CONTEXT, 

5609 input_token=None, 

5610 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5611 ): 

5612 if Context is None: 

5613 Context = self.CONTEXT(True) 

5614 Context.passive = True 

5615 

5616 if Context.state == self.STATE.INIT or ( 

5617 # In DCE/RPC, there's an extra AP-REP sent from the client. 

5618 Context.state == self.STATE.SRV_SENT_APREP 

5619 and req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5620 ): 

5621 Context, _, status = self.GSS_Accept_sec_context( 

5622 Context, 

5623 input_token=input_token, 

5624 req_flags=req_flags, 

5625 ) 

5626 if status in [GSS_S_CONTINUE_NEEDED, GSS_S_COMPLETE]: 

5627 Context.state = self.STATE.CLI_SENT_APREQ 

5628 else: 

5629 Context.state = self.STATE.FAILED 

5630 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5631 Context, _, status = self.GSS_Init_sec_context( 

5632 Context, 

5633 input_token=input_token, 

5634 req_flags=req_flags, 

5635 ) 

5636 if status == GSS_S_COMPLETE: 

5637 if req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5638 status = GSS_S_CONTINUE_NEEDED 

5639 Context.state = self.STATE.SRV_SENT_APREP 

5640 else: 

5641 Context.state == self.STATE.FAILED 

5642 else: 

5643 # Unknown state. Don't crash though. 

5644 status = GSS_S_FAILURE 

5645 

5646 return Context, status 

5647 

5648 def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False): 

5649 if Context.IsAcceptor is not IsAcceptor: 

5650 return 

5651 # Swap everything 

5652 Context.SendSealKeyUsage, Context.RecvSealKeyUsage = ( 

5653 Context.RecvSealKeyUsage, 

5654 Context.SendSealKeyUsage, 

5655 ) 

5656 Context.SendSignKeyUsage, Context.RecvSignKeyUsage = ( 

5657 Context.RecvSignKeyUsage, 

5658 Context.SendSignKeyUsage, 

5659 ) 

5660 Context.IsAcceptor = not Context.IsAcceptor 

5661 

5662 def LegsAmount(self, Context: CONTEXT): 

5663 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5664 return 4 

5665 else: 

5666 return 2 

5667 

5668 def MaximumSignatureLength(self, Context: CONTEXT): 

5669 if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG: 

5670 # TODO: support DES 

5671 if Context.KrbSessionKey.etype in [17, 18]: # AES 

5672 return 76 

5673 elif Context.KrbSessionKey.etype in [23, 24]: # RC4_HMAC 

5674 return 45 

5675 else: 

5676 raise NotImplementedError 

5677 else: 

5678 return 28