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

1751 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_BLOB, 

132 GSS_C_FLAGS, 

133 GSS_C_NO_CHANNEL_BINDINGS, 

134 GSS_S_BAD_BINDINGS, 

135 GSS_S_BAD_MECH, 

136 GSS_S_COMPLETE, 

137 GSS_S_CONTINUE_NEEDED, 

138 GSS_S_DEFECTIVE_TOKEN, 

139 GSS_S_DEFECTIVE_CREDENTIAL, 

140 GSS_S_FAILURE, 

141 GSS_S_FLAGS, 

142 GssChannelBindings, 

143 SSP, 

144 _GSSAPI_OIDS, 

145 _GSSAPI_SIGNATURE_OIDS, 

146) 

147from scapy.layers.inet import TCP, UDP 

148from scapy.layers.smb import _NV_VERSION 

149from scapy.layers.smb2 import STATUS_ERREF 

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.x509 import ( 

165 _CMS_ENCAPSULATED, 

166 CMS_ContentInfo, 

167 CMS_IssuerAndSerialNumber, 

168 DHPublicKey, 

169 X509_AlgorithmIdentifier, 

170 X509_DirectoryName, 

171 X509_SubjectPublicKeyInfo, 

172 DomainParameters, 

173) 

174 

175# Redirect exports from RFC3961 

176try: 

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

178 from scapy.libs.rfc3961 import ( 

179 _rfc1964pad, 

180 ChecksumType, 

181 Cipher, 

182 decrepit_algorithms, 

183 EncryptionType, 

184 Hmac_MD5, 

185 Key, 

186 KRB_FX_CF2, 

187 octetstring2key, 

188 ) 

189except ImportError: 

190 pass 

191 

192 

193# Crypto imports 

194if conf.crypto_valid: 

195 from cryptography.hazmat.primitives.serialization import pkcs12 

196 from cryptography.hazmat.primitives.asymmetric import dh 

197 

198# Typing imports 

199from typing import ( 

200 List, 

201 Optional, 

202 Union, 

203) 

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("AS_Result", ["asrep", "sessionkey", "kdcrep", "upn"]) 

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

3038 

3039 class MODE(IntEnum): 

3040 AS_REQ = 0 

3041 TGS_REQ = 1 

3042 GET_SALT = 2 

3043 

3044 def __init__( 

3045 self, 

3046 mode=MODE.AS_REQ, 

3047 ip: Optional[str] = None, 

3048 upn: Optional[str] = None, 

3049 password: Optional[str] = None, 

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

3051 realm: Optional[str] = None, 

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

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

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

3055 p12: Optional[str] = None, 

3056 spn: Optional[str] = None, 

3057 ticket: Optional[KRB_Ticket] = None, 

3058 host: Optional[str] = None, 

3059 renew: bool = False, 

3060 additional_tickets: List[KRB_Ticket] = [], 

3061 u2u: bool = False, 

3062 for_user: Optional[str] = None, 

3063 s4u2proxy: bool = False, 

3064 dmsa: bool = False, 

3065 kdc_proxy: Optional[str] = None, 

3066 kdc_proxy_no_check_certificate: bool = False, 

3067 fast: bool = False, 

3068 armor_ticket: KRB_Ticket = None, 

3069 armor_ticket_upn: Optional[str] = None, 

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

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

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

3073 pkinit_kex_method: PKINIT_KEX_METHOD = PKINIT_KEX_METHOD.DIFFIE_HELLMAN, 

3074 port: int = 88, 

3075 timeout: int = 5, 

3076 verbose: bool = True, 

3077 **kwargs, 

3078 ): 

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

3080 from scapy.layers.ldap import dclocator 

3081 

3082 if not upn: 

3083 raise ValueError("Invalid upn") 

3084 if not spn: 

3085 raise ValueError("Invalid spn") 

3086 if realm is None: 

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

3088 _, realm = _parse_upn(upn) 

3089 elif mode == self.MODE.TGS_REQ: 

3090 _, realm = _parse_spn(spn) 

3091 if not realm and ticket: 

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

3093 # of the ticket. 

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

3095 else: 

3096 raise ValueError("Invalid realm") 

3097 

3098 # PKINIT checks 

3099 if p12 is not None: 

3100 # password should be None or bytes 

3101 if isinstance(password, str): 

3102 password = password.encode() 

3103 

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

3105 # retry once. 

3106 while True: 

3107 try: 

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

3109 x509key, x509, _ = pkcs12.load_key_and_certificates( 

3110 fd.read(), 

3111 password=password, 

3112 ) 

3113 break 

3114 except ValueError as ex: 

3115 if password is None: 

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

3117 try: 

3118 from prompt_toolkit import prompt 

3119 

3120 password = prompt( 

3121 "Enter PKCS12 password: ", is_password=True 

3122 ) 

3123 except ImportError: 

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

3125 password = password.encode() 

3126 else: 

3127 raise ex 

3128 

3129 x509 = Cert(cryptography_obj=x509) 

3130 x509key = PrivKey(cryptography_obj=x509key) 

3131 elif x509 and x509key: 

3132 if not isinstance(x509, Cert): 

3133 x509 = Cert(x509) 

3134 if not isinstance(x509key, PrivKey): 

3135 x509key = PrivKey(x509key) 

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

3137 ca = CertList(ca) 

3138 

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

3140 if not host: 

3141 raise ValueError("Invalid host") 

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

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

3144 elif mode == self.MODE.TGS_REQ: 

3145 if not ticket: 

3146 raise ValueError("Invalid ticket") 

3147 

3148 if not ip and not kdc_proxy: 

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

3150 ip = dclocator( 

3151 realm, 

3152 timeout=timeout, 

3153 # Use connect mode instead of ldap for compatibility 

3154 # with MIT kerberos servers 

3155 mode="connect", 

3156 port=port, 

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

3158 ).ip 

3159 

3160 # Armoring checks 

3161 if fast: 

3162 if mode == self.MODE.AS_REQ: 

3163 # Requires an external ticket 

3164 if not armor_ticket or not armor_ticket_upn or not armor_ticket_skey: 

3165 raise ValueError( 

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

3167 "please provide the 3 required armor arguments" 

3168 ) 

3169 elif mode == self.MODE.TGS_REQ: 

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

3171 raise ValueError( 

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

3173 ) 

3174 

3175 if mode == self.MODE.GET_SALT: 

3176 if etypes is not None: 

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

3178 

3179 etypes = [ 

3180 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3181 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3182 ] 

3183 elif etypes is None: 

3184 etypes = [ 

3185 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3186 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3187 EncryptionType.RC4_HMAC, 

3188 EncryptionType.RC4_HMAC_EXP, 

3189 EncryptionType.DES_CBC_MD5, 

3190 ] 

3191 self.etypes = etypes 

3192 

3193 self.mode = mode 

3194 

3195 self.result = None # Result 

3196 

3197 self._timeout = timeout 

3198 self._verbose = verbose 

3199 self._ip = ip 

3200 self._port = port 

3201 self.kdc_proxy = kdc_proxy 

3202 self.kdc_proxy_no_check_certificate = kdc_proxy_no_check_certificate 

3203 

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

3205 self.host = host.upper() 

3206 self.password = password and bytes_encode(password) 

3207 self.spn = spn 

3208 self.upn = upn 

3209 self.realm = realm.upper() 

3210 self.x509 = x509 

3211 self.x509key = x509key 

3212 self.pkinit_kex_method = pkinit_kex_method 

3213 self.ticket = ticket 

3214 self.fast = fast 

3215 self.armor_ticket = armor_ticket 

3216 self.armor_ticket_upn = armor_ticket_upn 

3217 self.armor_ticket_skey = armor_ticket_skey 

3218 self.key_list_req = key_list_req 

3219 self.renew = renew 

3220 self.additional_tickets = additional_tickets # U2U + S4U2Proxy 

3221 self.u2u = u2u # U2U 

3222 self.for_user = for_user # FOR-USER 

3223 self.s4u2proxy = s4u2proxy # S4U2Proxy 

3224 self.dmsa = dmsa # DMSA 

3225 self.key = key 

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

3227 self.replykey = None # Key used for reply 

3228 # See RFC4120 - sect 7.2.2 

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

3230 self.should_followup = False 

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

3232 self.fast_req_sent = False 

3233 # Session parameters 

3234 self.pre_auth = False 

3235 self.fast_rep = None 

3236 self.fast_error = None 

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

3238 self.fast_armorkey = None # The armor key 

3239 self.fxcookie = None 

3240 self.pkinit_dh_key = None 

3241 if ca is not None: 

3242 self.pkinit_cms = CMS_Engine(ca) 

3243 else: 

3244 self.pkinit_cms = None 

3245 

3246 sock = self._connect() 

3247 super(KerberosClient, self).__init__( 

3248 sock=sock, 

3249 **kwargs, 

3250 ) 

3251 

3252 def _connect(self): 

3253 """ 

3254 Internal function to bind a socket to the DC. 

3255 This also takes care of an eventual KDC proxy. 

3256 """ 

3257 if self.kdc_proxy: 

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

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

3260 sock = KdcProxySocket( 

3261 url=self.kdc_proxy, 

3262 targetDomain=self.realm, 

3263 no_check_certificate=self.kdc_proxy_no_check_certificate, 

3264 ) 

3265 else: 

3266 sock = socket.socket() 

3267 sock.settimeout(self._timeout) 

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

3269 sock = StreamSocket(sock, KerberosTCPHeader) 

3270 return sock 

3271 

3272 def send(self, pkt): 

3273 """ 

3274 Sends a wrapped Kerberos packet 

3275 """ 

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

3277 

3278 def _show_krb_error(self, error): 

3279 """ 

3280 Displays a Kerberos error 

3281 """ 

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

3283 # KDC_ERR_S_PRINCIPAL_UNKNOWN 

3284 if ( 

3285 isinstance(error.root.eData, KERB_ERROR_UNK) 

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

3287 ): 

3288 log_runtime.error( 

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

3290 ) 

3291 else: 

3292 log_runtime.error( 

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

3294 % error.root.getSPN() 

3295 ) 

3296 else: 

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

3298 if self._verbose: 

3299 error.show() 

3300 

3301 def _base_kdc_req(self, now_time): 

3302 """ 

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

3304 """ 

3305 kdcreq = KRB_KDC_REQ_BODY( 

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

3307 additionalTickets=None, 

3308 # Windows default 

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

3310 cname=None, 

3311 realm=ASN1_GENERAL_STRING(self.realm), 

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

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

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

3315 ) 

3316 if self.renew: 

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

3318 return kdcreq 

3319 

3320 def calc_fast_armorkey(self): 

3321 """ 

3322 Calculate and return the FAST armorkey 

3323 """ 

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

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

3326 # AS-REQ mode 

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

3328 

3329 self.fast_armorkey = KRB_FX_CF2( 

3330 self.fast_skey, 

3331 self.armor_ticket_skey, 

3332 b"subkeyarmor", 

3333 b"ticketarmor", 

3334 ) 

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

3336 # TGS-REQ: 2 cases 

3337 

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

3339 

3340 if not self.armor_ticket: 

3341 # Case 1: Implicit armoring 

3342 self.fast_armorkey = KRB_FX_CF2( 

3343 self.subkey, 

3344 self.key, 

3345 b"subkeyarmor", 

3346 b"ticketarmor", 

3347 ) 

3348 else: 

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

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

3351 

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

3353 

3354 explicit_armor_key = KRB_FX_CF2( 

3355 self.fast_skey, 

3356 self.armor_ticket_skey, 

3357 b"subkeyarmor", 

3358 b"ticketarmor", 

3359 ) 

3360 

3361 self.fast_armorkey = KRB_FX_CF2( 

3362 explicit_armor_key, 

3363 self.subkey, 

3364 b"explicitarmor", 

3365 b"tgsarmor", 

3366 ) 

3367 

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

3369 """ 

3370 :param kdc_req: the KDC_REQ_BODY to wrap 

3371 :param padata: the list of PADATA to wrap 

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

3373 """ 

3374 

3375 # Create the PA Fast request wrapper 

3376 pafastreq = PA_FX_FAST_REQUEST( 

3377 armoredData=KrbFastArmoredReq( 

3378 reqChecksum=Checksum(), 

3379 encFastReq=EncryptedData(), 

3380 ) 

3381 ) 

3382 

3383 if self.armor_ticket is not None: 

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

3385 

3386 pafastreq.armoredData.armor = KrbFastArmor( 

3387 armorType=1, # FX_FAST_ARMOR_AP_REQUEST 

3388 armorValue=KRB_AP_REQ( 

3389 ticket=self.armor_ticket, 

3390 authenticator=EncryptedData(), 

3391 ), 

3392 ) 

3393 

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

3395 _, crealm = _parse_upn(self.armor_ticket_upn) 

3396 authenticator = KRB_Authenticator( 

3397 crealm=ASN1_GENERAL_STRING(crealm), 

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

3399 cksum=None, 

3400 ctime=ASN1_GENERALIZED_TIME(now_time), 

3401 cusec=ASN1_INTEGER(0), 

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

3403 seqNumber=ASN1_INTEGER(0), 

3404 encAuthorizationData=None, 

3405 ) 

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

3407 self.armor_ticket_skey, 

3408 authenticator, 

3409 ) 

3410 

3411 # Sign the fast request wrapper 

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

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

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

3415 pafastreq.armoredData.reqChecksum.make( 

3416 self.fast_armorkey, 

3417 bytes(pa_tgsreq_ap), 

3418 ) 

3419 else: 

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

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

3422 # containing message" 

3423 pafastreq.armoredData.reqChecksum.make( 

3424 self.fast_armorkey, 

3425 bytes(kdc_req), 

3426 ) 

3427 

3428 # Build and encrypt the Fast request 

3429 fastreq = KrbFastReq( 

3430 padata=padata, 

3431 reqBody=kdc_req, 

3432 ) 

3433 pafastreq.armoredData.encFastReq.encrypt( 

3434 self.fast_armorkey, 

3435 fastreq, 

3436 ) 

3437 

3438 # Return the PADATA 

3439 return PADATA( 

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

3441 padataValue=pafastreq, 

3442 ) 

3443 

3444 def as_req(self): 

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

3446 

3447 # 1. Build and populate KDC-REQ 

3448 kdc_req = self._base_kdc_req(now_time=now_time) 

3449 kdc_req.addresses = [ 

3450 HostAddress( 

3451 addrType=ASN1_INTEGER(20), # Netbios 

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

3453 ) 

3454 ] 

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

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

3457 

3458 # 2. Build the list of PADATA 

3459 padata = [ 

3460 PADATA( 

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

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

3463 ) 

3464 ] 

3465 

3466 # Cookie support 

3467 if self.fxcookie: 

3468 padata.insert( 

3469 0, 

3470 PADATA( 

3471 padataType=133, # PA-FX-COOKIE 

3472 padataValue=self.fxcookie, 

3473 ), 

3474 ) 

3475 

3476 # FAST 

3477 if self.fast: 

3478 # Calculate the armor key 

3479 self.calc_fast_armorkey() 

3480 

3481 # [MS-KILE] sect 3.2.5.5 

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

3483 padata.append( 

3484 PADATA( 

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

3486 padataValue=PA_PAC_OPTIONS( 

3487 options="Claims", 

3488 ), 

3489 ) 

3490 ) 

3491 

3492 # Pre-auth is requested 

3493 if self.pre_auth: 

3494 if self.x509: 

3495 # Special PKINIT (RFC4556) factor 

3496 

3497 # RFC4556 - 3.2.1. Generation of Client Request 

3498 

3499 # RFC4556 - 3.2.1 - (5) AuthPack 

3500 authpack = KRB_AuthPack( 

3501 pkAuthenticator=KRB_PKAuthenticator( 

3502 ctime=ASN1_GENERALIZED_TIME(now_time), 

3503 cusec=ASN1_INTEGER(0), 

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

3505 ), 

3506 clientPublicValue=None, # Used only in DH mode 

3507 supportedCMSTypes=None, 

3508 clientDHNonce=None, 

3509 supportedKDFs=None, 

3510 ) 

3511 

3512 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

3513 # RFC4556 - 3.2.3.1. Diffie-Hellman Key Exchange 

3514 

3515 # We use modp2048 

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

3517 self.pkinit_dh_key = dh_parameters.generate_private_key() 

3518 numbers = dh_parameters.parameter_numbers() 

3519 

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

3521 # and we want the DomainParameters format. 

3522 authpack.clientPublicValue = X509_SubjectPublicKeyInfo( 

3523 signatureAlgorithm=X509_AlgorithmIdentifier( 

3524 algorithm=ASN1_OID("dhpublicnumber"), 

3525 parameters=DomainParameters( 

3526 p=ASN1_INTEGER(numbers.p), 

3527 g=ASN1_INTEGER(numbers.g), 

3528 # q: see ERRATA 1 of RFC4556 

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

3530 ), 

3531 ), 

3532 subjectPublicKey=DHPublicKey( 

3533 y=ASN1_INTEGER( 

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

3535 ), 

3536 ), 

3537 ) 

3538 elif self.pkinit_kex_method == PKINIT_KEX_METHOD.PUBLIC_KEY: 

3539 # RFC4556 - 3.2.3.2. - Public Key Encryption 

3540 

3541 # Set supportedCMSTypes, supportedKDFs 

3542 authpack.supportedCMSTypes = [ 

3543 X509_AlgorithmIdentifier(algorithm=ASN1_OID(x)) 

3544 for x in [ 

3545 "ecdsa-with-SHA512", 

3546 "ecdsa-with-SHA256", 

3547 "sha512WithRSAEncryption", 

3548 "sha256WithRSAEncryption", 

3549 ] 

3550 ] 

3551 authpack.supportedKDFs = [ 

3552 KDFAlgorithmId(kdfId=ASN1_OID(x)) 

3553 for x in [ 

3554 "id-pkinit-kdf-sha256", 

3555 "id-pkinit-kdf-sha1", 

3556 "id-pkinit-kdf-sha512", 

3557 ] 

3558 ] 

3559 

3560 # XXX UNFINISHED 

3561 raise NotImplementedError 

3562 else: 

3563 raise ValueError 

3564 

3565 # Populate paChecksum and PAChecksum2 

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

3567 

3568 # Sign the AuthPack 

3569 signedAuthpack = self.pkinit_cms.sign( 

3570 authpack, 

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

3572 self.x509, 

3573 self.x509key, 

3574 ) 

3575 

3576 # Build PA-DATA 

3577 pafactor = PADATA( 

3578 padataType=16, # PA-PK-AS-REQ 

3579 padataValue=PA_PK_AS_REQ( 

3580 signedAuthpack=signedAuthpack, 

3581 trustedCertifiers=None, 

3582 kdcPkId=None, 

3583 ), 

3584 ) 

3585 else: 

3586 # Key-based factor 

3587 

3588 if self.fast: 

3589 # Special FAST factor 

3590 # RFC6113 sect 5.4.6 

3591 

3592 # Calculate the 'challenge key' 

3593 ts_key = KRB_FX_CF2( 

3594 self.fast_armorkey, 

3595 self.key, 

3596 b"clientchallengearmor", 

3597 b"challengelongterm", 

3598 ) 

3599 pafactor = PADATA( 

3600 padataType=138, # PA-ENCRYPTED-CHALLENGE 

3601 padataValue=EncryptedData(), 

3602 ) 

3603 else: 

3604 # Usual 'timestamp' factor 

3605 ts_key = self.key 

3606 pafactor = PADATA( 

3607 padataType=2, # PA-ENC-TIMESTAMP 

3608 padataValue=EncryptedData(), 

3609 ) 

3610 pafactor.padataValue.encrypt( 

3611 ts_key, 

3612 PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), 

3613 ) 

3614 

3615 # Insert Pre-Authentication data 

3616 padata.insert( 

3617 0, 

3618 pafactor, 

3619 ) 

3620 

3621 # FAST support 

3622 if self.fast: 

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

3624 # hidden inside the encrypted section. 

3625 padata = [ 

3626 self._fast_wrap( 

3627 kdc_req=kdc_req, 

3628 padata=padata, 

3629 now_time=now_time, 

3630 ) 

3631 ] 

3632 

3633 # 3. Build the request 

3634 asreq = Kerberos( 

3635 root=KRB_AS_REQ( 

3636 padata=padata, 

3637 reqBody=kdc_req, 

3638 ) 

3639 ) 

3640 

3641 # Note the reply key 

3642 self.replykey = self.key 

3643 

3644 return asreq 

3645 

3646 def tgs_req(self): 

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

3648 

3649 # Compute armor key for FAST 

3650 if self.fast: 

3651 self.calc_fast_armorkey() 

3652 

3653 # 1. Build and populate KDC-REQ 

3654 kdc_req = self._base_kdc_req(now_time=now_time) 

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

3656 

3657 # Additional tickets 

3658 if self.additional_tickets: 

3659 kdc_req.additionalTickets = self.additional_tickets 

3660 

3661 # U2U 

3662 if self.u2u: 

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

3664 

3665 # 2. Build the list of PADATA 

3666 padata = [] 

3667 

3668 # [MS-SFU] FOR-USER extension 

3669 if self.for_user is not None: 

3670 # [MS-SFU] note 4: 

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

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

3673 # certificate is available. 

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

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

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

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

3678 

3679 # 1. Add PA_S4U_X509_USER 

3680 pasfux509 = PA_S4U_X509_USER( 

3681 userId=S4UUserID( 

3682 nonce=kdc_req.nonce, 

3683 # [MS-SFU] note 5: 

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

3685 options="USE_REPLY_KEY_USAGE", 

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

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

3688 subjectCertificate=None, # TODO 

3689 ), 

3690 checksum=Checksum(), 

3691 ) 

3692 

3693 if self.dmsa: 

3694 # DMSA = set UNCONDITIONAL_DELEGATION to 1 

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

3696 

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

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

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

3700 pasfux509.checksum.make( 

3701 self.key, 

3702 bytes(pasfux509.userId), 

3703 cksumtype=ChecksumType.RSA_MD4, 

3704 ) 

3705 else: 

3706 pasfux509.checksum.make( 

3707 self.key, 

3708 bytes(pasfux509.userId), 

3709 ) 

3710 padata.append( 

3711 PADATA( 

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

3713 padataValue=pasfux509, 

3714 ) 

3715 ) 

3716 

3717 # 2. Add PA_FOR_USER 

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

3719 paforuser = PA_FOR_USER( 

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

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

3722 cksum=Checksum(), 

3723 ) 

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

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

3726 ) + ( 

3727 ( 

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

3729 + paforuser.userRealm.val 

3730 + paforuser.authPackage.val 

3731 ).encode() 

3732 ) 

3733 paforuser.cksum.make( 

3734 self.key, 

3735 S4UByteArray, 

3736 cksumtype=ChecksumType.HMAC_MD5, 

3737 ) 

3738 padata.append( 

3739 PADATA( 

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

3741 padataValue=paforuser, 

3742 ) 

3743 ) 

3744 

3745 # [MS-SFU] S4U2proxy - sect 3.1.5.2.1 

3746 if self.s4u2proxy: 

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

3748 padata.append( 

3749 PADATA( 

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

3751 padataValue=PA_PAC_OPTIONS( 

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

3753 ), 

3754 ) 

3755 ) 

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

3757 kdc_req.kdcOptions.set(14, 1) 

3758 

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

3760 if self.key_list_req: 

3761 padata.append( 

3762 PADATA( 

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

3764 padataValue=KERB_KEY_LIST_REQ( 

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

3766 ), 

3767 ) 

3768 ) 

3769 

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

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

3772 pa_tgs_req = PADATA( 

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

3774 padataValue=apreq, 

3775 ) 

3776 

3777 # 4. Populate it's authenticator 

3778 _, crealm = _parse_upn(self.upn) 

3779 authenticator = KRB_Authenticator( 

3780 crealm=ASN1_GENERAL_STRING(crealm), 

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

3782 cksum=None, 

3783 ctime=ASN1_GENERALIZED_TIME(now_time), 

3784 cusec=ASN1_INTEGER(0), 

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

3786 seqNumber=None, 

3787 encAuthorizationData=None, 

3788 ) 

3789 

3790 # Compute checksum 

3791 if self.key.cksumtype: 

3792 authenticator.cksum = Checksum() 

3793 authenticator.cksum.make( 

3794 self.key, 

3795 bytes(kdc_req), 

3796 ) 

3797 

3798 # Encrypt authenticator 

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

3800 

3801 # 5. Process FAST if required 

3802 if self.fast: 

3803 padata = [ 

3804 self._fast_wrap( 

3805 kdc_req=kdc_req, 

3806 padata=padata, 

3807 now_time=now_time, 

3808 pa_tgsreq_ap=apreq, 

3809 ) 

3810 ] 

3811 

3812 # 6. Add the final PADATA 

3813 padata.append(pa_tgs_req) 

3814 

3815 # 7. Build the request 

3816 tgsreq = Kerberos( 

3817 root=KRB_TGS_REQ( 

3818 padata=padata, 

3819 reqBody=kdc_req, 

3820 ) 

3821 ) 

3822 

3823 # Note the reply key 

3824 if self.subkey: 

3825 self.replykey = self.subkey 

3826 else: 

3827 self.replykey = self.key 

3828 

3829 return tgsreq 

3830 

3831 @ATMT.state(initial=1) 

3832 def BEGIN(self): 

3833 pass 

3834 

3835 @ATMT.condition(BEGIN) 

3836 def should_send_as_req(self): 

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

3838 raise self.SENT_AS_REQ() 

3839 

3840 @ATMT.condition(BEGIN) 

3841 def should_send_tgs_req(self): 

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

3843 raise self.SENT_TGS_REQ() 

3844 

3845 @ATMT.action(should_send_as_req) 

3846 def send_as_req(self): 

3847 self.send(self.as_req()) 

3848 

3849 @ATMT.action(should_send_tgs_req) 

3850 def send_tgs_req(self): 

3851 self.send(self.tgs_req()) 

3852 

3853 @ATMT.state() 

3854 def SENT_AS_REQ(self): 

3855 pass 

3856 

3857 @ATMT.state() 

3858 def SENT_TGS_REQ(self): 

3859 pass 

3860 

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

3862 """ 

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

3864 

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

3866 """ 

3867 salt = b"" 

3868 

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

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

3871 

3872 # 1. Process pa-data 

3873 if padatas is not None: 

3874 for padata in padatas: 

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

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

3877 elt = padata.padataValue.seq[0] 

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

3879 etype = elt.etype.val 

3880 if etype != EncryptionType.RC4_HMAC: 

3881 salt = elt.salt.val 

3882 

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

3884 # PKINIT handling 

3885 

3886 # The steps are as follows: 

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

3888 # is different depending on the used method. 

3889 # 2. Compute the replykey 

3890 

3891 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

3892 # Unpack KDCDHKeyInfo 

3893 keyinfo = self.pkinit_cms.verify( 

3894 padata.padataValue.rep.dhSignedData, 

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

3896 ) 

3897 

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

3899 # the CMS successfully, end here. 

3900 if etype is None: 

3901 continue 

3902 

3903 # Extract crypto parameters 

3904 y = keyinfo.subjectPublicKey.y.val 

3905 

3906 # Import into cryptography 

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

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

3909 

3910 # Calculate DHSharedSecret 

3911 DHSharedSecret = self.pkinit_dh_key.exchange(pubkey) 

3912 

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

3914 self.replykey = octetstring2key( 

3915 etype, 

3916 DHSharedSecret, 

3917 ) 

3918 

3919 else: 

3920 raise ValueError 

3921 

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

3923 # Get cookie and store it 

3924 self.fxcookie = padata.padataValue 

3925 

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

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

3928 if isinstance(padata.padataValue, PA_FX_FAST_REPLY): 

3929 self.fast_rep = ( 

3930 padata.padataValue.armoredData.encFastRep.decrypt( 

3931 self.fast_armorkey, 

3932 ) 

3933 ) 

3934 

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

3936 # Get error and store it 

3937 self.fast_error = padata.padataValue 

3938 

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

3940 # Verify S4U checksum 

3941 key_usage_number = None 

3942 pasfux509 = padata.padataValue 

3943 # [MS-SFU] sect 2.2.2 

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

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

3946 key_usage_number = 27 

3947 pasfux509.checksum.verify( 

3948 self.key, 

3949 bytes(pasfux509.userId), 

3950 key_usage_number=key_usage_number, 

3951 ) 

3952 

3953 # 2. Update the current keys if necessary 

3954 

3955 # Compute client key if not already provided 

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

3957 self.key = Key.string_to_key( 

3958 etype, 

3959 self.password, 

3960 salt, 

3961 ) 

3962 

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

3964 if self.fast_rep and self.fast_rep.strengthenKey: 

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

3966 self.replykey = KRB_FX_CF2( 

3967 self.fast_rep.strengthenKey.toKey(), 

3968 self.replykey, 

3969 b"strengthenkey", 

3970 b"replykey", 

3971 ) 

3972 

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

3974 def receive_salt_mode(self, pkt): 

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

3976 # exit. 

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

3978 if Kerberos not in pkt: 

3979 raise self.FINAL() 

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

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

3982 raise self.FINAL() 

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

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

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

3986 elt = padata.padataValue.seq[0] 

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

3988 self.result = elt.salt.val 

3989 raise self.FINAL() 

3990 else: 

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

3992 raise self.FINAL() 

3993 

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

3995 def receive_krb_error_as_req(self, pkt): 

3996 # We check for Kerberos errors. 

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

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

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

4000 # Process PAs if available 

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

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

4003 

4004 # Special case for FAST errors 

4005 if self.fast_rep: 

4006 # This is actually a fast response error ! 

4007 frep, self.fast_rep = self.fast_rep, None 

4008 # Re-process PAs 

4009 self._process_padatas_and_key(frep.padata) 

4010 # Extract real Kerberos error from FAST message 

4011 ferr = Kerberos(root=self.fast_error) 

4012 self.fast_error = None 

4013 # Recurse 

4014 self.receive_krb_error_as_req(ferr) 

4015 return 

4016 

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

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

4019 log_runtime.error( 

4020 "Got 'KDC_ERR_PREAUTH_REQUIRED', " 

4021 "but no possible key could be computed." 

4022 ) 

4023 raise self.FINAL() 

4024 self.should_followup = True 

4025 self.pre_auth = True 

4026 raise self.BEGIN() 

4027 else: 

4028 self._show_krb_error(pkt) 

4029 raise self.FINAL() 

4030 

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

4032 def receive_as_rep(self, pkt): 

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

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

4035 

4036 @ATMT.eof(SENT_AS_REQ) 

4037 def retry_after_eof_in_apreq(self): 

4038 if self.should_followup: 

4039 # Reconnect and Restart 

4040 self.should_followup = False 

4041 self.update_sock(self._connect()) 

4042 raise self.BEGIN() 

4043 else: 

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

4045 raise self.FINAL() 

4046 

4047 @ATMT.action(receive_as_rep) 

4048 def decrypt_as_rep(self, pkt): 

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

4050 self._process_padatas_and_key( 

4051 pkt.root.padata, 

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

4053 ) 

4054 

4055 if not self.pre_auth: 

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

4057 

4058 # Process FAST response 

4059 if self.fast_rep: 

4060 # Verify the ticket-checksum 

4061 self.fast_rep.finished.ticketChecksum.verify( 

4062 self.fast_armorkey, 

4063 bytes(pkt.root.ticket), 

4064 ) 

4065 self.fast_rep = None 

4066 elif self.fast: 

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

4068 

4069 # Check for PKINIT 

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

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

4072 

4073 # Decrypt AS-REP response 

4074 enc = pkt.root.encPart 

4075 res = enc.decrypt(self.replykey) 

4076 self.result = self.RES_AS_MODE( 

4077 pkt.root, 

4078 res.key.toKey(), 

4079 res, 

4080 pkt.root.getUPN(), 

4081 ) 

4082 

4083 @ATMT.receive_condition(SENT_TGS_REQ) 

4084 def receive_krb_error_tgs_req(self, pkt): 

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

4086 # Process PAs if available 

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

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

4089 

4090 if self.fast_rep: 

4091 # This is actually a fast response error ! 

4092 frep, self.fast_rep = self.fast_rep, None 

4093 # Re-process PAs 

4094 self._process_padatas_and_key(frep.padata) 

4095 # Extract real Kerberos error from FAST message 

4096 ferr = Kerberos(root=self.fast_error) 

4097 self.fast_error = None 

4098 # Recurse 

4099 self.receive_krb_error_tgs_req(ferr) 

4100 return 

4101 

4102 self._show_krb_error(pkt) 

4103 raise self.FINAL() 

4104 

4105 @ATMT.receive_condition(SENT_TGS_REQ) 

4106 def receive_tgs_rep(self, pkt): 

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

4108 if ( 

4109 not self.renew 

4110 and not self.dmsa 

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

4112 ): 

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

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

4115 

4116 @ATMT.action(receive_tgs_rep) 

4117 def decrypt_tgs_rep(self, pkt): 

4118 self._process_padatas_and_key(pkt.root.padata) 

4119 

4120 # Process FAST response 

4121 if self.fast_rep: 

4122 # Verify the ticket-checksum 

4123 self.fast_rep.finished.ticketChecksum.verify( 

4124 self.fast_armorkey, 

4125 bytes(pkt.root.ticket), 

4126 ) 

4127 self.fast_rep = None 

4128 elif self.fast: 

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

4130 

4131 # Decrypt TGS-REP response 

4132 enc = pkt.root.encPart 

4133 if self.subkey: 

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

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

4136 # authenticator subkey is used." 

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

4138 else: 

4139 res = enc.decrypt(self.replykey) 

4140 

4141 # Store result 

4142 self.result = self.RES_TGS_MODE( 

4143 pkt.root, 

4144 res.key.toKey(), 

4145 res, 

4146 self.upn, 

4147 ) 

4148 

4149 @ATMT.state(final=1) 

4150 def FINAL(self): 

4151 pass 

4152 

4153 

4154def _parse_upn(upn): 

4155 """ 

4156 Extract the username and realm from full UPN 

4157 """ 

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

4159 if not m: 

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

4161 if "/" in upn: 

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

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

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

4165 raise ValueError(err) 

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

4167 user = m.group(1) 

4168 domain = m.group(3) 

4169 else: 

4170 user = m.group(3) 

4171 domain = m.group(1) 

4172 return user, domain 

4173 

4174 

4175def _parse_spn(spn): 

4176 """ 

4177 Extract ServiceName and realm from full SPN 

4178 """ 

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

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

4181 if not m: 

4182 try: 

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

4184 return _parse_upn(spn) 

4185 except ValueError: 

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

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

4188 

4189 

4190def _spn_are_equal(spn1, spn2): 

4191 """ 

4192 Check that two SPNs are equal. 

4193 """ 

4194 spn1, _ = _parse_spn(spn1) 

4195 spn2, _ = _parse_spn(spn2) 

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

4197 

4198 

4199def krb_as_req( 

4200 upn: str, 

4201 spn: Optional[str] = None, 

4202 ip: Optional[str] = None, 

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

4204 password: Optional[str] = None, 

4205 realm: Optional[str] = None, 

4206 host: str = "WIN10", 

4207 p12: Optional[str] = None, 

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

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

4210 **kwargs, 

4211): 

4212 r""" 

4213 Kerberos AS-Req 

4214 

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

4216 or "user@DOMAIN" 

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

4218 Defaults to "krbtgt/<realm>" 

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

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

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

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

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

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

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

4226 'password' is the password of the p12. 

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

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

4229 

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

4231 

4232 Example:: 

4233 

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

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

4236 

4237 Equivalent:: 

4238 

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

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

4241 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

4243 

4244 Example using PKINIT with a p12:: 

4245 

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

4247 """ 

4248 if realm is None: 

4249 _, realm = _parse_upn(upn) 

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

4251 if password is None: 

4252 try: 

4253 from prompt_toolkit import prompt 

4254 

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

4256 except ImportError: 

4257 password = input("Enter password: ") 

4258 cli = KerberosClient( 

4259 mode=KerberosClient.MODE.AS_REQ, 

4260 realm=realm, 

4261 ip=ip, 

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

4263 host=host, 

4264 upn=upn, 

4265 password=password, 

4266 key=key, 

4267 p12=p12, 

4268 x509=x509, 

4269 x509key=x509key, 

4270 **kwargs, 

4271 ) 

4272 cli.run() 

4273 cli.stop() 

4274 return cli.result 

4275 

4276 

4277def krb_tgs_req( 

4278 upn, 

4279 spn, 

4280 sessionkey, 

4281 ticket, 

4282 ip=None, 

4283 renew=False, 

4284 realm=None, 

4285 additional_tickets=[], 

4286 u2u=False, 

4287 etypes=None, 

4288 for_user=None, 

4289 s4u2proxy=False, 

4290 **kwargs, 

4291): 

4292 r""" 

4293 Kerberos TGS-Req 

4294 

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

4296 or "user@DOMAIN" 

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

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

4299 :param ticket: the tgt ticket 

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

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

4302 :param renew: ask for renewal 

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

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

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

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

4307 :param etypes: array of EncryptionType values. 

4308 By default: AES128, AES256, RC4, DES_MD5 

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

4310 S4U2Self extension. 

4311 

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

4313 

4314 Example:: 

4315 

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

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

4318 

4319 Equivalent:: 

4320 

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

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

4323 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

4325 """ 

4326 cli = KerberosClient( 

4327 mode=KerberosClient.MODE.TGS_REQ, 

4328 realm=realm, 

4329 upn=upn, 

4330 ip=ip, 

4331 spn=spn, 

4332 key=sessionkey, 

4333 ticket=ticket, 

4334 renew=renew, 

4335 additional_tickets=additional_tickets, 

4336 u2u=u2u, 

4337 etypes=etypes, 

4338 for_user=for_user, 

4339 s4u2proxy=s4u2proxy, 

4340 **kwargs, 

4341 ) 

4342 cli.run() 

4343 cli.stop() 

4344 return cli.result 

4345 

4346 

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

4348 """ 

4349 Kerberos AS-Req then TGS-Req 

4350 """ 

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

4352 if not res: 

4353 return 

4354 

4355 return krb_tgs_req( 

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

4357 spn=spn, 

4358 sessionkey=res.sessionkey, 

4359 ticket=res.asrep.ticket, 

4360 ip=ip, 

4361 **kwargs, 

4362 ) 

4363 

4364 

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

4366 """ 

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

4368 """ 

4369 if realm is None: 

4370 _, realm = _parse_upn(upn) 

4371 cli = KerberosClient( 

4372 mode=KerberosClient.MODE.GET_SALT, 

4373 realm=realm, 

4374 ip=ip, 

4375 spn="krbtgt/" + realm, 

4376 upn=upn, 

4377 host=host, 

4378 **kwargs, 

4379 ) 

4380 cli.run() 

4381 cli.stop() 

4382 return cli.result 

4383 

4384 

4385def kpasswd( 

4386 upn, 

4387 targetupn=None, 

4388 ip=None, 

4389 password=None, 

4390 newpassword=None, 

4391 key=None, 

4392 ticket=None, 

4393 realm=None, 

4394 ssp=None, 

4395 setpassword=None, 

4396 timeout=3, 

4397 port=464, 

4398 debug=0, 

4399 **kwargs, 

4400): 

4401 """ 

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

4403 

4404 :param upn: the UPN to use for authentication 

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

4406 same as upn. 

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

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

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

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

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

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

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

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

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

4416 """ 

4417 from scapy.layers.ldap import dclocator 

4418 

4419 if not realm: 

4420 _, realm = _parse_upn(upn) 

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

4422 if ip is None: 

4423 ip = dclocator( 

4424 realm, 

4425 timeout=timeout, 

4426 # Use connect mode instead of ldap for compatibility 

4427 # with MIT kerberos servers 

4428 mode="connect", 

4429 port=port, 

4430 debug=debug, 

4431 ).ip 

4432 if ssp is None and ticket is not None: 

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

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

4435 if tktspn == "krbtgt": 

4436 log_runtime.info( 

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

4438 ) 

4439 setpassword = True 

4440 resp = krb_tgs_req( 

4441 upn=upn, 

4442 spn=spn, 

4443 ticket=ticket, 

4444 sessionkey=key, 

4445 ip=ip, 

4446 debug=debug, 

4447 ) 

4448 if resp is None: 

4449 return 

4450 ticket = resp.tgsrep.ticket 

4451 key = resp.sessionkey 

4452 if setpassword is None: 

4453 setpassword = bool(targetupn) 

4454 elif setpassword and targetupn is None: 

4455 targetupn = upn 

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

4457 # Get a ticket for kadmin/changepw 

4458 if ssp is None: 

4459 if ticket is None: 

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

4461 resp = krb_as_req( 

4462 upn=upn, 

4463 spn=spn, 

4464 key=key, 

4465 ip=ip, 

4466 password=password, 

4467 debug=debug, 

4468 ) 

4469 if resp is None: 

4470 return 

4471 ticket = resp.asrep.ticket 

4472 key = resp.sessionkey 

4473 ssp = KerberosSSP( 

4474 UPN=upn, 

4475 SPN=spn, 

4476 ST=ticket, 

4477 KEY=key, 

4478 DC_IP=ip, 

4479 debug=debug, 

4480 **kwargs, 

4481 ) 

4482 Context, tok, status = ssp.GSS_Init_sec_context( 

4483 None, 

4484 req_flags=0, # No GSS_C_MUTUAL_FLAG 

4485 ) 

4486 if status != GSS_S_CONTINUE_NEEDED: 

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

4488 if tok: 

4489 tok.show() 

4490 return 

4491 apreq = tok.innerToken.root 

4492 # Connect 

4493 sock = socket.socket() 

4494 sock.settimeout(timeout) 

4495 sock.connect((ip, port)) 

4496 sock = StreamSocket(sock, KpasswdTCPHeader) 

4497 # Do KPASSWD request 

4498 if newpassword is None: 

4499 try: 

4500 from prompt_toolkit import prompt 

4501 

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

4503 except ImportError: 

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

4505 krbpriv = KRB_PRIV(encPart=EncryptedData()) 

4506 krbpriv.encPart.encrypt( 

4507 Context.KrbSessionKey, 

4508 EncKrbPrivPart( 

4509 sAddress=HostAddress( 

4510 addrType=ASN1_INTEGER(2), # IPv4 

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

4512 ), 

4513 userData=ASN1_STRING( 

4514 bytes( 

4515 ChangePasswdData( 

4516 newpasswd=newpassword, 

4517 targname=PrincipalName.fromUPN(targetupn), 

4518 targrealm=realm, 

4519 ) 

4520 ) 

4521 if setpassword 

4522 else newpassword 

4523 ), 

4524 timestamp=None, 

4525 usec=None, 

4526 seqNumber=Context.SendSeqNum, 

4527 ), 

4528 ) 

4529 resp = sock.sr1( 

4530 KpasswdTCPHeader() 

4531 / KPASSWD_REQ( 

4532 pvno=0xFF80 if setpassword else 1, 

4533 apreq=apreq, 

4534 krbpriv=krbpriv, 

4535 ), 

4536 timeout=timeout, 

4537 verbose=0, 

4538 ) 

4539 # Verify KPASSWD response 

4540 if not resp: 

4541 raise TimeoutError("KPASSWD_REQ timed out !") 

4542 if KPASSWD_REP not in resp: 

4543 resp.show() 

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

4545 Context, tok, status = ssp.GSS_Init_sec_context( 

4546 Context, 

4547 input_token=resp.aprep, 

4548 ) 

4549 if status != GSS_S_COMPLETE: 

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

4551 if tok: 

4552 tok.show() 

4553 return 

4554 # Parse answer KRB_PRIV 

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

4556 userRep = KPasswdRepData(krbanswer.userData.val) 

4557 if userRep.resultCode != 0: 

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

4559 userRep.show() 

4560 return 

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

4562 

4563 

4564# SSP 

4565 

4566 

4567class KerberosSSP(SSP): 

4568 """ 

4569 The KerberosSSP 

4570 

4571 Client settings: 

4572 

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

4574 If not provided, will be retrieved 

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

4576 target_name provided in the GSS_Init_sec_context 

4577 :param UPN: The client UPN 

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

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

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

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

4582 OR the session key associated with the TGT 

4583 OR the kerberos key associated with the UPN 

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

4585 password of the UPN. 

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

4587 

4588 Server settings: 

4589 

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

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

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

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

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

4595 this IP using using the KEY when using U2U. 

4596 """ 

4597 

4598 auth_type = 0x10 

4599 

4600 class STATE(SSP.STATE): 

4601 INIT = 1 

4602 CLI_SENT_TGTREQ = 2 

4603 CLI_SENT_APREQ = 3 

4604 CLI_RCVD_APREP = 4 

4605 SRV_SENT_APREP = 5 

4606 FAILED = -1 

4607 

4608 class CONTEXT(SSP.CONTEXT): 

4609 __slots__ = [ 

4610 "SessionKey", 

4611 "ServerHostname", 

4612 "U2U", 

4613 "KrbSessionKey", # raw Key object 

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

4615 "SeqNum", # for AP 

4616 "SendSeqNum", # for MIC 

4617 "RecvSeqNum", # for MIC 

4618 "IsAcceptor", 

4619 "SendSealKeyUsage", 

4620 "SendSignKeyUsage", 

4621 "RecvSealKeyUsage", 

4622 "RecvSignKeyUsage", 

4623 # server-only 

4624 "UPN", 

4625 "PAC", 

4626 ] 

4627 

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

4629 self.state = KerberosSSP.STATE.INIT 

4630 self.SessionKey = None 

4631 self.ServerHostname = None 

4632 self.U2U = False 

4633 self.SendSeqNum = 0 

4634 self.RecvSeqNum = 0 

4635 self.KrbSessionKey = None 

4636 self.STSessionKey = None 

4637 self.IsAcceptor = IsAcceptor 

4638 self.UPN = None 

4639 self.PAC = None 

4640 # [RFC 4121] sect 2 

4641 if IsAcceptor: 

4642 self.SendSealKeyUsage = 22 

4643 self.SendSignKeyUsage = 23 

4644 self.RecvSealKeyUsage = 24 

4645 self.RecvSignKeyUsage = 25 

4646 else: 

4647 self.SendSealKeyUsage = 24 

4648 self.SendSignKeyUsage = 25 

4649 self.RecvSealKeyUsage = 22 

4650 self.RecvSignKeyUsage = 23 

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

4652 

4653 def clifailure(self): 

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

4655 

4656 def __repr__(self): 

4657 if self.U2U: 

4658 return "KerberosSSP-U2U" 

4659 return "KerberosSSP" 

4660 

4661 def __init__( 

4662 self, 

4663 ST=None, 

4664 UPN=None, 

4665 PASSWORD=None, 

4666 U2U=False, 

4667 KEY=None, 

4668 SPN=None, 

4669 TGT=None, 

4670 DC_IP=None, 

4671 SKEY_TYPE=None, 

4672 debug=0, 

4673 **kwargs, 

4674 ): 

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

4676 

4677 self.ST = ST 

4678 self.UPN = UPN 

4679 self.KEY = KEY 

4680 self.SPN = SPN 

4681 self.TGT = TGT 

4682 self.TGTSessionKey = None 

4683 self.PASSWORD = PASSWORD 

4684 self.U2U = U2U 

4685 self.DC_IP = DC_IP 

4686 self.debug = debug 

4687 if SKEY_TYPE is None: 

4688 SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96 

4689 self.SKEY_TYPE = SKEY_TYPE 

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

4691 

4692 def GSS_Inquire_names_for_mech(self): 

4693 mechs = [ 

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

4695 "1.2.840.113554.1.2.2", # Kerberos 5 

4696 ] 

4697 if self.U2U: 

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

4699 return mechs 

4700 

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

4702 """ 

4703 [MS-KILE] sect 3.4.5.6 

4704 

4705 - AES: RFC4121 sect 4.2.6.1 

4706 """ 

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

4708 # Concatenate the ToSign 

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

4710 sig = KRB_InnerToken( 

4711 TOK_ID=b"\x04\x04", 

4712 root=KRB_GSS_MIC( 

4713 Flags="AcceptorSubkey" 

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

4715 SND_SEQ=Context.SendSeqNum, 

4716 ), 

4717 ) 

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

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

4720 keyusage=Context.SendSignKeyUsage, 

4721 text=ToSign, 

4722 ) 

4723 else: 

4724 raise NotImplementedError 

4725 Context.SendSeqNum += 1 

4726 return sig 

4727 

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

4729 """ 

4730 [MS-KILE] sect 3.4.5.7 

4731 

4732 - AES: RFC4121 sect 4.2.6.1 

4733 """ 

4734 Context.RecvSeqNum = signature.root.SND_SEQ 

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

4736 # Concatenate the ToSign 

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

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

4739 sig = Context.KrbSessionKey.make_checksum( 

4740 keyusage=Context.RecvSignKeyUsage, 

4741 text=ToSign, 

4742 ) 

4743 else: 

4744 raise NotImplementedError 

4745 if sig != signature.root.SGN_CKSUM: 

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

4747 

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

4749 """ 

4750 [MS-KILE] sect 3.4.5.4 

4751 

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

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

4754 """ 

4755 # Is confidentiality in use? 

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

4757 x.conf_req_flag for x in msgs 

4758 ) 

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

4760 # Build token 

4761 tok = KRB_InnerToken( 

4762 TOK_ID=b"\x05\x04", 

4763 root=KRB_GSS_Wrap( 

4764 Flags="AcceptorSubkey" 

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

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

4767 SND_SEQ=Context.SendSeqNum, 

4768 RRC=0, 

4769 ), 

4770 ) 

4771 Context.SendSeqNum += 1 

4772 # Real separation starts now: RFC4121 sect 4.2.4 

4773 if confidentiality: 

4774 # Confidentiality is requested (see RFC4121 sect 4.3) 

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

4776 # 0. Roll confounder 

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

4778 # 1. Concatenate the data to be encrypted 

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

4780 DataLen = len(Data) 

4781 # 2. Add filler 

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

4783 # be zero" 

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

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

4786 Data += Filler 

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

4788 PlainHeader = bytes(tok)[:16] 

4789 Data += PlainHeader 

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

4791 ToSign = Confounder 

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

4793 ToSign += Filler 

4794 ToSign += PlainHeader 

4795 # 5. Finalize token for signing 

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

4797 tok.root.RRC = 28 

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

4799 # integrity protection) 

4800 Data = Context.KrbSessionKey.encrypt( 

4801 keyusage=Context.SendSealKeyUsage, 

4802 plaintext=Data, 

4803 confounder=Confounder, 

4804 signtext=ToSign, 

4805 ) 

4806 # 7. Rotate 

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

4808 # 8. Split (token and encrypted messages) 

4809 toklen = len(Data) - DataLen 

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

4811 offset = toklen 

4812 for msg in msgs: 

4813 msglen = len(msg.data) 

4814 if msg.conf_req_flag: 

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

4816 offset += msglen 

4817 return msgs, tok 

4818 else: 

4819 # No confidentiality is requested 

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

4821 # 0. Concatenate the data 

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

4823 DataLen = len(Data) 

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

4825 ToSign = Data 

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

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

4828 # checksum mechanism 

4829 Mic = Context.KrbSessionKey.make_checksum( 

4830 keyusage=Context.SendSealKeyUsage, 

4831 text=ToSign, 

4832 ) 

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

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

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

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

4837 # is requested" 

4838 tok.root.RRC = 12 

4839 # 3. Concat and pack 

4840 for msg in msgs: 

4841 if msg.sign: 

4842 msg.data = b"" 

4843 Data = Data + Mic 

4844 # 4. Rotate 

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

4846 return msgs, tok 

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

4848 # Build token 

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

4850 tok = KRB_InnerToken( 

4851 TOK_ID=b"\x02\x01", 

4852 root=KRB_GSS_Wrap_RFC1964( 

4853 SGN_ALG="HMAC", 

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

4855 SND_SEQ=seq 

4856 + ( 

4857 # See errata 

4858 b"\xff\xff\xff\xff" 

4859 if Context.IsAcceptor 

4860 else b"\x00\x00\x00\x00" 

4861 ), 

4862 ), 

4863 ) 

4864 Context.SendSeqNum += 1 

4865 # 0. Concatenate data 

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

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

4868 Kss = Context.KrbSessionKey.key 

4869 # 1. Roll confounder 

4870 Confounder = os.urandom(8) 

4871 # 2. Compute the 'Kseq' key 

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

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

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

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

4876 else: 

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

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

4879 # 3. Build SGN_CKSUM 

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

4881 keyusage=13, # See errata 

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

4883 )[:8] 

4884 # 4. Populate token + encrypt 

4885 if confidentiality: 

4886 # 'encrypt' is requested 

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

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

4889 Data = rc4.update(ToEncrypt) 

4890 # Split encrypted data 

4891 offset = 0 

4892 for msg in msgs: 

4893 msglen = len(msg.data) 

4894 if msg.conf_req_flag: 

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

4896 offset += msglen 

4897 else: 

4898 # 'encrypt' is not requested 

4899 tok.root.CONFOUNDER = Confounder 

4900 # 5. Compute the 'Kseq' key 

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

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

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

4904 else: 

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

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

4907 # 6. Encrypt 'SND_SEQ' 

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

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

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

4911 tok = KRB_GSSAPI_Token( 

4912 MechType="1.2.840.113554.1.2.2", # Kerberos 5 

4913 innerToken=tok, 

4914 ) 

4915 return msgs, tok 

4916 else: 

4917 raise NotImplementedError 

4918 

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

4920 """ 

4921 [MS-KILE] sect 3.4.5.5 

4922 

4923 - AES: RFC4121 sect 4.2.6.2 

4924 - HMAC-RC4: RFC4757 sect 7.3 

4925 """ 

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

4927 confidentiality = signature.root.Flags.Sealed 

4928 # Real separation starts now: RFC4121 sect 4.2.4 

4929 if confidentiality: 

4930 # 0. Concatenate the data 

4931 Data = signature.root.Data 

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

4933 # 1. Un-Rotate 

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

4935 

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

4937 def MakeToSign(Confounder, DecText): 

4938 offset = 0 

4939 # 2.a Confounder 

4940 ToSign = Confounder 

4941 # 2.b Messages 

4942 for msg in msgs: 

4943 msglen = len(msg.data) 

4944 if msg.conf_req_flag: 

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

4946 offset += msglen 

4947 elif msg.sign: 

4948 ToSign += msg.data 

4949 # 2.c Filler & Padding 

4950 ToSign += DecText[offset:] 

4951 return ToSign 

4952 

4953 # 3. Decrypt 

4954 Data = Context.KrbSessionKey.decrypt( 

4955 keyusage=Context.RecvSealKeyUsage, 

4956 ciphertext=Data, 

4957 presignfunc=MakeToSign, 

4958 ) 

4959 # 4. Split 

4960 Data, f16header = ( 

4961 Data[:-16], 

4962 Data[-16:], 

4963 ) 

4964 # 5. Check header 

4965 hdr = signature.copy() 

4966 hdr.root.RRC = 0 

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

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

4969 # 6. Split (and ignore filler) 

4970 offset = 0 

4971 for msg in msgs: 

4972 msglen = len(msg.data) 

4973 if msg.conf_req_flag: 

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

4975 offset += msglen 

4976 # Case without msgs 

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

4978 msgs[0].data = Data 

4979 return msgs 

4980 else: 

4981 # No confidentiality is requested 

4982 # 0. Concatenate the data 

4983 Data = signature.root.Data 

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

4985 # 1. Un-Rotate 

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

4987 # 2. Split 

4988 Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :] 

4989 # "Both the EC field and the RRC field in 

4990 # the token header SHALL be filled with zeroes for the purpose of 

4991 # calculating the checksum." 

4992 ToSign = Data 

4993 hdr = signature.copy() 

4994 hdr.root.RRC = 0 

4995 hdr.root.EC = 0 

4996 # Concatenate the data 

4997 ToSign += bytes(hdr)[:16] 

4998 # 3. Calculate the signature 

4999 sig = Context.KrbSessionKey.make_checksum( 

5000 keyusage=Context.RecvSealKeyUsage, 

5001 text=ToSign, 

5002 ) 

5003 # 4. Compare 

5004 if sig != Mic: 

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

5006 # Case without msgs 

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

5008 msgs[0].data = Data 

5009 return msgs 

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

5011 # Drop wrapping 

5012 tok = signature.innerToken 

5013 

5014 # Detect confidentiality 

5015 confidentiality = tok.root.SEAL_ALG != 0xFFFF 

5016 

5017 # 0. Concatenate data 

5018 ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

5019 Kss = Context.KrbSessionKey.key 

5020 # 1. Compute the 'Kseq' key 

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

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

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

5024 else: 

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

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

5027 # 2. Decrypt 'SND_SEQ' 

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

5029 seq = rc4.update(tok.root.SND_SEQ)[:4] 

5030 # 3. Compute the 'Kcrypt' key 

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

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

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

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

5035 else: 

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

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

5038 # 4. Decrypt 

5039 if confidentiality: 

5040 # 'encrypt' was requested 

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

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

5043 Data = rc4.update(ToDecrypt) 

5044 # Split encrypted data 

5045 offset = 0 

5046 for msg in msgs: 

5047 msglen = len(msg.data) 

5048 if msg.conf_req_flag: 

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

5050 offset += msglen 

5051 else: 

5052 # 'encrypt' was not requested 

5053 Confounder = tok.root.CONFOUNDER 

5054 # 5. Verify SGN_CKSUM 

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

5056 Context.KrbSessionKey.verify_checksum( 

5057 keyusage=13, # See errata 

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

5059 cksum=tok.root.SGN_CKSUM, 

5060 ) 

5061 return msgs 

5062 else: 

5063 raise NotImplementedError 

5064 

5065 def GSS_Init_sec_context( 

5066 self, 

5067 Context: CONTEXT, 

5068 input_token=None, 

5069 target_name: Optional[str] = None, 

5070 req_flags: Optional[GSS_C_FLAGS] = None, 

5071 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5072 ): 

5073 if Context is None: 

5074 # New context 

5075 Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags) 

5076 

5077 if Context.state == self.STATE.INIT and self.U2U: 

5078 # U2U - Get TGT 

5079 Context.state = self.STATE.CLI_SENT_TGTREQ 

5080 return ( 

5081 Context, 

5082 KRB_GSSAPI_Token( 

5083 MechType="1.2.840.113554.1.2.2.3", # U2U 

5084 innerToken=KRB_InnerToken( 

5085 TOK_ID=b"\x04\x00", 

5086 root=KRB_TGT_REQ(), 

5087 ), 

5088 ), 

5089 GSS_S_CONTINUE_NEEDED, 

5090 ) 

5091 

5092 if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]: 

5093 if not self.UPN: 

5094 raise ValueError("Missing UPN attribute") 

5095 

5096 # Do we have a ST? 

5097 if self.ST is None: 

5098 # Client sends an AP-req 

5099 if not self.SPN and not target_name: 

5100 raise ValueError("Missing SPN/target_name attribute") 

5101 additional_tickets = [] 

5102 

5103 if self.U2U: 

5104 try: 

5105 # GSSAPI / Kerberos 

5106 tgt_rep = input_token.root.innerToken.root 

5107 except AttributeError: 

5108 try: 

5109 # Kerberos 

5110 tgt_rep = input_token.innerToken.root 

5111 except AttributeError: 

5112 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5113 if not isinstance(tgt_rep, KRB_TGT_REP): 

5114 tgt_rep.show() 

5115 raise ValueError("KerberosSSP: Unexpected input_token !") 

5116 additional_tickets = [tgt_rep.ticket] 

5117 

5118 if self.TGT is None: 

5119 # Get TGT. We were passed a kerberos key 

5120 res = krb_as_req( 

5121 upn=self.UPN, 

5122 ip=self.DC_IP, 

5123 key=self.KEY, 

5124 password=self.PASSWORD, 

5125 debug=self.debug, 

5126 verbose=bool(self.debug), 

5127 ) 

5128 if res is None: 

5129 # Failed to retrieve the ticket 

5130 return Context, None, GSS_S_FAILURE 

5131 

5132 # Update UPN (could have been canonicalized) 

5133 self.UPN = res.upn 

5134 

5135 # Store TGT, 

5136 self.TGT = res.asrep.ticket 

5137 self.TGTSessionKey = res.sessionkey 

5138 else: 

5139 # We have a TGT and were passed its key 

5140 self.TGTSessionKey = self.KEY 

5141 

5142 # Get ST 

5143 if not self.TGTSessionKey: 

5144 raise ValueError("Cannot use TGT without the KEY") 

5145 

5146 res = krb_tgs_req( 

5147 upn=self.UPN, 

5148 spn=self.SPN or target_name, 

5149 ip=self.DC_IP, 

5150 sessionkey=self.TGTSessionKey, 

5151 ticket=self.TGT, 

5152 additional_tickets=additional_tickets, 

5153 u2u=self.U2U, 

5154 debug=self.debug, 

5155 verbose=bool(self.debug), 

5156 ) 

5157 if not res: 

5158 # Failed to retrieve the ticket 

5159 return Context, None, GSS_S_FAILURE 

5160 

5161 # Store the service ticket and associated key 

5162 self.ST, Context.STSessionKey = res.tgsrep.ticket, res.sessionkey 

5163 elif not self.KEY: 

5164 raise ValueError("Must provide KEY with ST") 

5165 else: 

5166 # We were passed a ST and its key 

5167 Context.STSessionKey = self.KEY 

5168 

5169 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5170 raise ValueError( 

5171 "Cannot use GSS_C_DELEG_FLAG when passed a service ticket !" 

5172 ) 

5173 

5174 # Save ServerHostname 

5175 if len(self.ST.sname.nameString) == 2: 

5176 Context.ServerHostname = self.ST.sname.nameString[1].val.decode() 

5177 

5178 # Build the KRB-AP 

5179 apOptions = ASN1_BIT_STRING("000") 

5180 if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG: 

5181 apOptions.set(2, "1") # mutual-required 

5182 if self.U2U: 

5183 apOptions.set(1, "1") # use-session-key 

5184 Context.U2U = True 

5185 ap_req = KRB_AP_REQ( 

5186 apOptions=apOptions, 

5187 ticket=self.ST, 

5188 authenticator=EncryptedData(), 

5189 ) 

5190 

5191 # Get the current time 

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

5193 # Pick a random session key 

5194 Context.KrbSessionKey = Key.new_random_key( 

5195 self.SKEY_TYPE, 

5196 ) 

5197 

5198 # We use a random SendSeqNum 

5199 Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix() 

5200 

5201 # Get the realm of the client 

5202 _, crealm = _parse_upn(self.UPN) 

5203 

5204 # Build the RFC4121 authenticator checksum 

5205 authenticator_checksum = KRB_AuthenticatorChecksum( 

5206 # RFC 4121 sect 4.1.1.2 

5207 # "The Bnd field contains the MD5 hash of channel bindings" 

5208 Bnd=( 

5209 chan_bindings.digestMD5() 

5210 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5211 else (b"\x00" * 16) 

5212 ), 

5213 Flags=int(Context.flags), 

5214 ) 

5215 

5216 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5217 # Delegate TGT 

5218 raise NotImplementedError("GSS_C_DELEG_FLAG is not implemented !") 

5219 # authenticator_checksum.Deleg = KRB_CRED( 

5220 # tickets=[self.TGT], 

5221 # encPart=EncryptedData() 

5222 # ) 

5223 # authenticator_checksum.encPart.encrypt( 

5224 # Context.STSessionKey, 

5225 # EncKrbCredPart( 

5226 # ticketInfo=KrbCredInfo( 

5227 # key=EncryptionKey.fromKey(self.TGTSessionKey), 

5228 # prealm=ASN1_GENERAL_STRING(crealm), 

5229 # pname=PrincipalName.fromUPN(self.UPN), 

5230 # # TODO: rework API to pass starttime... here. 

5231 # sreralm=self.TGT.realm, 

5232 # sname=self.TGT.sname, 

5233 # ) 

5234 # ) 

5235 # ) 

5236 

5237 # Build and encrypt the full KRB_Authenticator 

5238 ap_req.authenticator.encrypt( 

5239 Context.STSessionKey, 

5240 KRB_Authenticator( 

5241 crealm=crealm, 

5242 cname=PrincipalName.fromUPN(self.UPN), 

5243 cksum=Checksum( 

5244 cksumtype="KRB-AUTHENTICATOR", checksum=authenticator_checksum 

5245 ), 

5246 ctime=ASN1_GENERALIZED_TIME(now_time), 

5247 cusec=ASN1_INTEGER(0), 

5248 subkey=EncryptionKey.fromKey(Context.KrbSessionKey), 

5249 seqNumber=Context.SendSeqNum, 

5250 encAuthorizationData=AuthorizationData( 

5251 seq=[ 

5252 AuthorizationDataItem( 

5253 adType="AD-IF-RELEVANT", 

5254 adData=AuthorizationData( 

5255 seq=[ 

5256 AuthorizationDataItem( 

5257 adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

5258 adData=KERB_AD_RESTRICTION_ENTRY( 

5259 restriction=LSAP_TOKEN_INFO_INTEGRITY( 

5260 MachineID=bytes(RandBin(32)), 

5261 PermanentMachineID=bytes( 

5262 RandBin(32) 

5263 ), 

5264 ) 

5265 ), 

5266 ), 

5267 # This isn't documented, but sent on Windows :/ 

5268 AuthorizationDataItem( 

5269 adType="KERB-LOCAL", 

5270 adData=b"\x00" * 16, 

5271 ), 

5272 ] 

5273 + ( 

5274 # Channel bindings 

5275 [ 

5276 AuthorizationDataItem( 

5277 adType="AD-AUTH-DATA-AP-OPTIONS", 

5278 adData=KERB_AUTH_DATA_AP_OPTIONS( 

5279 apOptions="KERB_AP_OPTIONS_CBT" 

5280 ), 

5281 ) 

5282 ] 

5283 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5284 else [] 

5285 ) 

5286 ), 

5287 ) 

5288 ] 

5289 ), 

5290 ), 

5291 ) 

5292 Context.state = self.STATE.CLI_SENT_APREQ 

5293 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5294 # Raw kerberos DCE-STYLE 

5295 return Context, ap_req, GSS_S_CONTINUE_NEEDED 

5296 else: 

5297 # Kerberos wrapper 

5298 return ( 

5299 Context, 

5300 KRB_GSSAPI_Token( 

5301 innerToken=KRB_InnerToken( 

5302 root=ap_req, 

5303 ) 

5304 ), 

5305 GSS_S_CONTINUE_NEEDED, 

5306 ) 

5307 

5308 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5309 if isinstance(input_token, KRB_AP_REP): 

5310 # Raw AP_REP was passed 

5311 ap_rep = input_token 

5312 else: 

5313 try: 

5314 # GSSAPI / Kerberos 

5315 ap_rep = input_token.root.innerToken.root 

5316 except AttributeError: 

5317 try: 

5318 # Kerberos 

5319 ap_rep = input_token.innerToken.root 

5320 except AttributeError: 

5321 try: 

5322 # Raw kerberos DCE-STYLE 

5323 ap_rep = input_token.root 

5324 except AttributeError: 

5325 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5326 if not isinstance(ap_rep, KRB_AP_REP): 

5327 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5328 

5329 # Retrieve SessionKey 

5330 repPart = ap_rep.encPart.decrypt(Context.STSessionKey) 

5331 if repPart.subkey is not None: 

5332 Context.SessionKey = repPart.subkey.keyvalue.val 

5333 Context.KrbSessionKey = repPart.subkey.toKey() 

5334 

5335 # OK ! 

5336 Context.state = self.STATE.CLI_RCVD_APREP 

5337 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5338 # [MS-KILE] sect 3.4.5.1 

5339 # The client MUST generate an additional AP exchange reply message 

5340 # exactly as the server would as the final message to send to the 

5341 # server. 

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

5343 cli_ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5344 cli_ap_rep.encPart.encrypt( 

5345 Context.STSessionKey, 

5346 EncAPRepPart( 

5347 ctime=ASN1_GENERALIZED_TIME(now_time), 

5348 seqNumber=repPart.seqNumber, 

5349 subkey=None, 

5350 ), 

5351 ) 

5352 return Context, cli_ap_rep, GSS_S_COMPLETE 

5353 return Context, None, GSS_S_COMPLETE 

5354 elif ( 

5355 Context.state == self.STATE.CLI_RCVD_APREP 

5356 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5357 ): 

5358 # DCE_STYLE with SPNEGOSSP 

5359 return Context, None, GSS_S_COMPLETE 

5360 else: 

5361 raise ValueError("KerberosSSP: Unknown state") 

5362 

5363 def GSS_Accept_sec_context( 

5364 self, 

5365 Context: CONTEXT, 

5366 input_token=None, 

5367 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5368 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5369 ): 

5370 if Context is None: 

5371 # New context 

5372 Context = self.CONTEXT(IsAcceptor=True, req_flags=req_flags) 

5373 

5374 import scapy.layers.msrpce.mspac # noqa: F401 

5375 

5376 if Context.state == self.STATE.INIT: 

5377 if self.UPN and self.SPN: 

5378 raise ValueError("Cannot use SPN and UPN at the same time !") 

5379 if self.SPN and self.TGT: 

5380 raise ValueError("Cannot use TGT with SPN.") 

5381 if self.UPN and not self.TGT: 

5382 # UPN is provided: use U2U 

5383 res = krb_as_req( 

5384 self.UPN, 

5385 self.DC_IP, 

5386 key=self.KEY, 

5387 password=self.PASSWORD, 

5388 ) 

5389 self.TGT, self.KEY = res.asrep.ticket, res.sessionkey 

5390 

5391 # Server receives AP-req, sends AP-rep 

5392 if isinstance(input_token, KRB_AP_REQ): 

5393 # Raw AP_REQ was passed 

5394 ap_req = input_token 

5395 else: 

5396 try: 

5397 # GSSAPI/Kerberos 

5398 ap_req = input_token.root.innerToken.root 

5399 except AttributeError: 

5400 try: 

5401 # Kerberos 

5402 ap_req = input_token.innerToken.root 

5403 except AttributeError: 

5404 try: 

5405 # Raw kerberos 

5406 ap_req = input_token.root 

5407 except AttributeError: 

5408 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5409 

5410 if isinstance(ap_req, KRB_TGT_REQ): 

5411 # Special U2U case 

5412 Context.U2U = True 

5413 return ( 

5414 None, 

5415 KRB_GSSAPI_Token( 

5416 MechType="1.2.840.113554.1.2.2.3", # U2U 

5417 innerToken=KRB_InnerToken( 

5418 TOK_ID=b"\x04\x01", 

5419 root=KRB_TGT_REP( 

5420 ticket=self.TGT, 

5421 ), 

5422 ), 

5423 ), 

5424 GSS_S_CONTINUE_NEEDED, 

5425 ) 

5426 elif not isinstance(ap_req, KRB_AP_REQ): 

5427 ap_req.show() 

5428 raise ValueError("Unexpected type in KerberosSSP") 

5429 if not self.KEY: 

5430 raise ValueError("Missing KEY attribute") 

5431 

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

5433 

5434 # If using a UPN, require U2U 

5435 if self.UPN and ap_req.apOptions.val[1] != "1": # use-session-key 

5436 # Required but not provided. Return an error 

5437 Context.U2U = True 

5438 err = KRB_GSSAPI_Token( 

5439 innerToken=KRB_InnerToken( 

5440 TOK_ID=b"\x03\x00", 

5441 root=KRB_ERROR( 

5442 errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED", 

5443 stime=ASN1_GENERALIZED_TIME(now_time), 

5444 realm=ap_req.ticket.realm, 

5445 sname=ap_req.ticket.sname, 

5446 eData=KRB_TGT_REP( 

5447 ticket=self.TGT, 

5448 ), 

5449 ), 

5450 ) 

5451 ) 

5452 return Context, err, GSS_S_CONTINUE_NEEDED 

5453 

5454 # Validate the 'serverName' of the ticket. 

5455 sname = ap_req.ticket.getSPN() 

5456 our_sname = self.SPN or self.UPN 

5457 if not _spn_are_equal(our_sname, sname): 

5458 warning("KerberosSSP: bad server name: %s != %s" % (sname, our_sname)) 

5459 err = KRB_GSSAPI_Token( 

5460 innerToken=KRB_InnerToken( 

5461 TOK_ID=b"\x03\x00", 

5462 root=KRB_ERROR( 

5463 errorCode="KRB_AP_ERR_BADMATCH", 

5464 stime=ASN1_GENERALIZED_TIME(now_time), 

5465 realm=ap_req.ticket.realm, 

5466 sname=ap_req.ticket.sname, 

5467 eData=None, 

5468 ), 

5469 ) 

5470 ) 

5471 return Context, err, GSS_S_BAD_MECH 

5472 

5473 # Decrypt the ticket 

5474 try: 

5475 tkt = ap_req.ticket.encPart.decrypt(self.KEY) 

5476 except ValueError as ex: 

5477 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5478 err = KRB_GSSAPI_Token( 

5479 innerToken=KRB_InnerToken( 

5480 TOK_ID=b"\x03\x00", 

5481 root=KRB_ERROR( 

5482 errorCode="KRB_AP_ERR_MODIFIED", 

5483 stime=ASN1_GENERALIZED_TIME(now_time), 

5484 realm=ap_req.ticket.realm, 

5485 sname=ap_req.ticket.sname, 

5486 eData=None, 

5487 ), 

5488 ) 

5489 ) 

5490 return Context, err, GSS_S_DEFECTIVE_CREDENTIAL 

5491 

5492 # Store information about the user in the Context 

5493 if tkt.authorizationData and tkt.authorizationData.seq: 

5494 # Get AD-IF-RELEVANT 

5495 adIfRelevant = tkt.authorizationData.getAuthData(0x1) 

5496 if adIfRelevant: 

5497 # Get AD-WIN2K-PAC 

5498 Context.PAC = adIfRelevant.getAuthData(0x80) 

5499 

5500 # Get AP-REQ session key 

5501 Context.STSessionKey = tkt.key.toKey() 

5502 authenticator = ap_req.authenticator.decrypt(Context.STSessionKey) 

5503 

5504 # Compute an application session key ([MS-KILE] sect 3.1.1.2) 

5505 subkey = None 

5506 if ap_req.apOptions.val[2] == "1": # mutual-required 

5507 appkey = Key.new_random_key( 

5508 self.SKEY_TYPE, 

5509 ) 

5510 Context.KrbSessionKey = appkey 

5511 Context.SessionKey = appkey.key 

5512 subkey = EncryptionKey.fromKey(appkey) 

5513 else: 

5514 Context.KrbSessionKey = self.KEY 

5515 Context.SessionKey = self.KEY.key 

5516 

5517 # Eventually process the "checksum" 

5518 if authenticator.cksum and authenticator.cksum.cksumtype == 0x8003: 

5519 # KRB-Authenticator 

5520 authcksum = authenticator.cksum.checksum 

5521 Context.flags = authcksum.Flags 

5522 # Check channel bindings 

5523 if ( 

5524 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5525 and chan_bindings.digestMD5() != authcksum.Bnd 

5526 and not ( 

5527 GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS in req_flags 

5528 and authcksum.Bnd == GSS_C_NO_CHANNEL_BINDINGS 

5529 ) 

5530 ): 

5531 # Channel binding checks failed. 

5532 return Context, None, GSS_S_BAD_BINDINGS 

5533 elif ( 

5534 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5535 and GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS not in req_flags 

5536 ): 

5537 # Uhoh, we required channel bindings 

5538 return Context, None, GSS_S_BAD_BINDINGS 

5539 

5540 # Build response (RFC4120 sect 3.2.4) 

5541 ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5542 ap_rep.encPart.encrypt( 

5543 Context.STSessionKey, 

5544 EncAPRepPart( 

5545 ctime=authenticator.ctime, 

5546 cusec=authenticator.cusec, 

5547 seqNumber=None, 

5548 subkey=subkey, 

5549 ), 

5550 ) 

5551 Context.state = self.STATE.SRV_SENT_APREP 

5552 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5553 # [MS-KILE] sect 3.4.5.1 

5554 return Context, ap_rep, GSS_S_CONTINUE_NEEDED 

5555 return Context, ap_rep, GSS_S_COMPLETE # success 

5556 elif ( 

5557 Context.state == self.STATE.SRV_SENT_APREP 

5558 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5559 ): 

5560 # [MS-KILE] sect 3.4.5.1 

5561 # The server MUST receive the additional AP exchange reply message and 

5562 # verify that the message is constructed correctly. 

5563 if not input_token: 

5564 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5565 # Server receives AP-req, sends AP-rep 

5566 if isinstance(input_token, KRB_AP_REP): 

5567 # Raw AP_REP was passed 

5568 ap_rep = input_token 

5569 else: 

5570 try: 

5571 # GSSAPI/Kerberos 

5572 ap_rep = input_token.root.innerToken.root 

5573 except AttributeError: 

5574 try: 

5575 # Raw Kerberos 

5576 ap_rep = input_token.root 

5577 except AttributeError: 

5578 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5579 # Decrypt the AP-REP 

5580 try: 

5581 ap_rep.encPart.decrypt(Context.STSessionKey) 

5582 except ValueError as ex: 

5583 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5584 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5585 return Context, None, GSS_S_COMPLETE # success 

5586 else: 

5587 raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state)) 

5588 

5589 def GSS_Passive( 

5590 self, 

5591 Context: CONTEXT, 

5592 input_token=None, 

5593 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5594 ): 

5595 if Context is None: 

5596 Context = self.CONTEXT(True) 

5597 Context.passive = True 

5598 

5599 if Context.state == self.STATE.INIT or ( 

5600 # In DCE/RPC, there's an extra AP-REP sent from the client. 

5601 Context.state == self.STATE.SRV_SENT_APREP 

5602 and req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5603 ): 

5604 Context, _, status = self.GSS_Accept_sec_context( 

5605 Context, 

5606 input_token=input_token, 

5607 req_flags=req_flags, 

5608 ) 

5609 if status in [GSS_S_CONTINUE_NEEDED, GSS_S_COMPLETE]: 

5610 Context.state = self.STATE.CLI_SENT_APREQ 

5611 else: 

5612 Context.state = self.STATE.FAILED 

5613 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5614 Context, _, status = self.GSS_Init_sec_context( 

5615 Context, 

5616 input_token=input_token, 

5617 req_flags=req_flags, 

5618 ) 

5619 if status == GSS_S_COMPLETE: 

5620 if req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5621 status = GSS_S_CONTINUE_NEEDED 

5622 Context.state = self.STATE.SRV_SENT_APREP 

5623 else: 

5624 Context.state == self.STATE.FAILED 

5625 else: 

5626 # Unknown state. Don't crash though. 

5627 status = GSS_S_FAILURE 

5628 

5629 return Context, status 

5630 

5631 def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False): 

5632 if Context.IsAcceptor is not IsAcceptor: 

5633 return 

5634 # Swap everything 

5635 Context.SendSealKeyUsage, Context.RecvSealKeyUsage = ( 

5636 Context.RecvSealKeyUsage, 

5637 Context.SendSealKeyUsage, 

5638 ) 

5639 Context.SendSignKeyUsage, Context.RecvSignKeyUsage = ( 

5640 Context.RecvSignKeyUsage, 

5641 Context.SendSignKeyUsage, 

5642 ) 

5643 Context.IsAcceptor = not Context.IsAcceptor 

5644 

5645 def LegsAmount(self, Context: CONTEXT): 

5646 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5647 return 4 

5648 else: 

5649 return 2 

5650 

5651 def MaximumSignatureLength(self, Context: CONTEXT): 

5652 if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG: 

5653 # TODO: support DES 

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

5655 return 76 

5656 elif Context.KrbSessionKey.etype in [23, 24]: # RC4_HMAC 

5657 return 45 

5658 else: 

5659 raise NotImplementedError 

5660 else: 

5661 return 28