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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1893 statements  

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

2# This file is part of Scapy 

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

4# Copyright (C) Gabriel Potter 

5 

6r""" 

7Kerberos V5 

8 

9Implements parts of: 

10 

11- Kerberos Network Authentication Service (V5): RFC4120 

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

13- Kerberos Pre-Authentication: RFC6113 (FAST) 

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

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

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

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

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

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

20 draft-ietf-kitten-iakerb-03 

21- Kerberos Protocol Extensions: [MS-KILE] 

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

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

24 

25 

26.. note:: 

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

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

29 

30Example decryption:: 

31 

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

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

34 83c0a87a9cc0a87a11c209005854f6ab2392c25bd650182014b6e00000000001316a8201\ 

35 2d30820129a103020105a20302010aa3633061304ca103020102a24504433041a0030201\ 

36 12a23a043848484decb01c9b62a1cabfbc3f2d1ed85aa5e093ba8358a8cea34d4393af93\ 

37 bf211e274fa58e814878db9f0d7a28d94e7327660db4f3704b3011a10402020080a20904\ 

38 073005a0030101ffa481b73081b4a00703050040810010a1123010a003020101a1093007\ 

39 1b0577696e3124a20e1b0c444f4d41494e2e4c4f43414ca321301fa003020102a1183016\ 

40 1b066b72627467741b0c444f4d41494e2e4c4f43414ca511180f32303337303931333032\ 

41 343830355aa611180f32303337303931333032343830355aa7060204701cc5d1a8153013\ 

42 0201120201110201170201180202ff79020103a91d301b3019a003020114a11204105749\ 

43 4e31202020202020202020202020")) 

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

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

46 e87127a819d42e69b5e22de0ddc63da80096d")) 

47 >>> enc.decrypt(k) 

48""" 

49 

50from collections import namedtuple, deque 

51from datetime import datetime, timedelta, timezone 

52from enum import IntEnum 

53 

54import os 

55import re 

56import socket 

57import struct 

58import threading 

59 

60from scapy.error import warning 

61import scapy.asn1.mib # noqa: F401 

62from scapy.asn1.ber import BER_id_dec, BER_Decoding_Error 

63from scapy.asn1.asn1 import ( 

64 ASN1_BIT_STRING, 

65 ASN1_BOOLEAN, 

66 ASN1_Class, 

67 ASN1_Codecs, 

68 ASN1_GENERAL_STRING, 

69 ASN1_GENERALIZED_TIME, 

70 ASN1_INTEGER, 

71 ASN1_OID, 

72 ASN1_STRING, 

73 ASN1_UTF8_STRING, 

74) 

75from scapy.asn1fields import ( 

76 ASN1F_BIT_STRING_ENCAPS, 

77 ASN1F_BOOLEAN, 

78 ASN1F_CHOICE, 

79 ASN1F_enum_INTEGER, 

80 ASN1F_FLAGS, 

81 ASN1F_GENERAL_STRING, 

82 ASN1F_GENERALIZED_TIME, 

83 ASN1F_INTEGER, 

84 ASN1F_OID, 

85 ASN1F_optional, 

86 ASN1F_PACKET, 

87 ASN1F_SEQUENCE_OF, 

88 ASN1F_SEQUENCE, 

89 ASN1F_STRING_ENCAPS, 

90 ASN1F_STRING_PacketField, 

91 ASN1F_STRING, 

92 ASN1F_UTF8_STRING, 

93) 

94from scapy.asn1packet import ASN1_Packet 

95from scapy.automaton import Automaton, ATMT, ObjectPipe 

96from scapy.config import conf 

97from scapy.compat import bytes_encode 

98from scapy.error import log_runtime 

99from scapy.fields import ( 

100 ConditionalField, 

101 FieldLenField, 

102 FlagsField, 

103 IntEnumField, 

104 IntField, 

105 LEIntEnumField, 

106 LEShortEnumField, 

107 LEShortField, 

108 LenField, 

109 LongField, 

110 MayEnd, 

111 MultipleTypeField, 

112 PacketField, 

113 PacketLenField, 

114 PacketListField, 

115 PadField, 

116 ScalingField, 

117 ShortEnumField, 

118 ShortField, 

119 StrField, 

120 StrFieldUtf16, 

121 StrFixedLenEnumField, 

122 XByteField, 

123 XLEIntEnumField, 

124 XLEIntField, 

125 XLEShortField, 

126 XStrField, 

127 XStrFixedLenField, 

128 XStrLenField, 

129) 

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

131from scapy.supersocket import StreamSocket, SuperSocket 

132from scapy.utils import strrot, strxor 

133from scapy.volatile import GeneralizedTime, RandNum, RandBin 

134 

135from scapy.layers.gssapi import ( 

136 _GSSAPI_OIDS, 

137 _GSSAPI_SIGNATURE_OIDS, 

138 GSS_C_FLAGS, 

139 GSS_C_NO_CHANNEL_BINDINGS, 

140 GSS_QOP_REQ_FLAGS, 

141 GSS_S_BAD_BINDINGS, 

142 GSS_S_BAD_MECH, 

143 GSS_S_COMPLETE, 

144 GSS_S_CONTINUE_NEEDED, 

145 GSS_S_DEFECTIVE_CREDENTIAL, 

146 GSS_S_DEFECTIVE_TOKEN, 

147 GSS_S_FAILURE, 

148 GSS_S_FLAGS, 

149 GSSAPI_BLOB, 

150 GssChannelBindings, 

151 SSP, 

152) 

153from scapy.layers.inet import TCP, UDP 

154from scapy.layers.smb import _NV_VERSION 

155from scapy.layers.tls.cert import ( 

156 Cert, 

157 CertList, 

158 CertTree, 

159 CMS_Engine, 

160 PrivKey, 

161) 

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

163 Hash_SHA, 

164 Hash_SHA256, 

165 Hash_SHA384, 

166 Hash_SHA512, 

167) 

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

169from scapy.layers.windows.erref import STATUS_ERREF 

170from scapy.layers.x509 import ( 

171 _CMS_ENCAPSULATED, 

172 CMS_ContentInfo, 

173 CMS_IssuerAndSerialNumber, 

174 DHPublicKey, 

175 X509_AlgorithmIdentifier, 

176 X509_DirectoryName, 

177 X509_SubjectPublicKeyInfo, 

178 DomainParameters, 

179) 

180 

181# Redirect exports from RFC3961 

182try: 

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

184 from scapy.libs.rfc3961 import ( 

185 _rfc1964pad, 

186 ChecksumType, 

187 Cipher, 

188 decrepit_algorithms, 

189 EncryptionType, 

190 Hmac_MD5, 

191 Key, 

192 KRB_FX_CF2, 

193 octetstring2key, 

194 ) 

195except ImportError: 

196 pass 

197 

198 

199# Crypto imports 

200if conf.crypto_valid: 

201 from cryptography.hazmat.primitives.serialization import pkcs12 

202 from cryptography.hazmat.primitives.asymmetric import dh 

203 

204# Typing imports 

205from typing import ( 

206 List, 

207 Optional, 

208 Union, 

209) 

210 

211# kerberos APPLICATION 

212 

213 

214class ASN1_Class_KRB(ASN1_Class): 

215 name = "Kerberos" 

216 # APPLICATION + CONSTRUCTED = 0x40 | 0x20 

217 Token = 0x60 | 0 # GSSAPI 

218 Ticket = 0x60 | 1 

219 Authenticator = 0x60 | 2 

220 EncTicketPart = 0x60 | 3 

221 AS_REQ = 0x60 | 10 

222 AS_REP = 0x60 | 11 

223 TGS_REQ = 0x60 | 12 

224 TGS_REP = 0x60 | 13 

225 AP_REQ = 0x60 | 14 

226 AP_REP = 0x60 | 15 

227 PRIV = 0x60 | 21 

228 CRED = 0x60 | 22 

229 EncASRepPart = 0x60 | 25 

230 EncTGSRepPart = 0x60 | 26 

231 EncAPRepPart = 0x60 | 27 

232 EncKrbPrivPart = 0x60 | 28 

233 EncKrbCredPart = 0x60 | 29 

234 ERROR = 0x60 | 30 

235 

236 

237# RFC4120 sect 5.2 

238 

239 

240KerberosString = ASN1F_GENERAL_STRING 

241Realm = KerberosString 

242Int32 = ASN1F_INTEGER 

243UInt32 = ASN1F_INTEGER 

244 

245_PRINCIPAL_NAME_TYPES = { 

246 0: "NT-UNKNOWN", 

247 1: "NT-PRINCIPAL", 

248 2: "NT-SRV-INST", 

249 3: "NT-SRV-HST", 

250 4: "NT-SRV-XHST", 

251 5: "NT-UID", 

252 6: "NT-X500-PRINCIPAL", 

253 7: "NT-SMTP-NAME", 

254 10: "NT-ENTERPRISE", 

255} 

256 

257 

258class PrincipalName(ASN1_Packet): 

259 ASN1_codec = ASN1_Codecs.BER 

260 ASN1_root = ASN1F_SEQUENCE( 

261 ASN1F_enum_INTEGER( 

262 "nameType", 

263 0, 

264 _PRINCIPAL_NAME_TYPES, 

265 explicit_tag=0xA0, 

266 ), 

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

268 ) 

269 

270 def toString(self): 

271 """ 

272 Convert a PrincipalName back into its string representation. 

273 """ 

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

275 

276 @staticmethod 

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

278 """ 

279 Create a PrincipalName from a UPN string. 

280 """ 

281 if canonicalize: 

282 return PrincipalName( 

283 nameString=[ASN1_GENERAL_STRING(upn)], 

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

285 ) 

286 else: 

287 user, _ = _parse_upn(upn) 

288 return PrincipalName( 

289 nameString=[ASN1_GENERAL_STRING(user)], 

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

291 ) 

292 

293 @staticmethod 

294 def fromSPN(spn: str): 

295 """ 

296 Create a PrincipalName from a SPN string. 

297 """ 

298 spn, _ = _parse_spn(spn) 

299 if spn.startswith("krbtgt"): 

300 return PrincipalName( 

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

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

303 ) 

304 elif "/" in spn: 

305 return PrincipalName( 

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

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

308 ) 

309 else: 

310 # In case of U2U 

311 return PrincipalName( 

312 nameString=[ASN1_GENERAL_STRING(spn)], 

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

314 ) 

315 

316 

317KerberosTime = ASN1F_GENERALIZED_TIME 

318Microseconds = ASN1F_INTEGER 

319 

320 

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

322 

323_KRB_E_TYPES = { 

324 1: "DES-CBC-CRC", 

325 2: "DES-CBC-MD4", 

326 3: "DES-CBC-MD5", 

327 5: "DES3-CBC-MD5", 

328 7: "DES3-CBC-SHA1", 

329 9: "DSAWITHSHA1-CMSOID", 

330 10: "MD5WITHRSAENCRYPTION-CMSOID", 

331 11: "SHA1WITHRSAENCRYPTION-CMSOID", 

332 12: "RC2CBC-ENVOID", 

333 13: "RSAENCRYPTION-ENVOID", 

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

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

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

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

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

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

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

341 23: "RC4-HMAC", 

342 24: "RC4-HMAC-EXP", 

343 25: "CAMELLIA128-CTS-CMAC", 

344 26: "CAMELLIA256-CTS-CMAC", 

345} 

346 

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

348 

349_KRB_S_TYPES = { 

350 1: "CRC32", 

351 2: "RSA-MD4", 

352 3: "RSA-MD4-DES", 

353 4: "DES-MAC", 

354 5: "DES-MAC-K", 

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

356 7: "RSA-MD5", 

357 8: "RSA-MD5-DES", 

358 9: "RSA-MD5-DES3", 

359 10: "SHA1", 

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

361 13: "HMAC-SHA1-DES3", 

362 14: "SHA1", 

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

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

365 17: "CMAC-CAMELLIA128", 

366 18: "CMAC-CAMELLIA256", 

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

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

369 # RFC 4121 

370 0x8003: "KRB-AUTHENTICATOR", 

371 # [MS-KILE] 

372 0xFFFFFF76: "MD5", 

373 -138: "MD5", 

374} 

375 

376 

377class EncryptedData(ASN1_Packet): 

378 ASN1_codec = ASN1_Codecs.BER 

379 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

383 ) 

384 

385 def get_usage(self): 

386 """ 

387 Get current key usage number and encrypted class 

388 """ 

389 # RFC 4120 sect 7.5.1 

390 if self.underlayer: 

391 if isinstance(self.underlayer, PADATA): 

392 patype = self.underlayer.padataType 

393 if patype == 2: 

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

395 return 1, PA_ENC_TS_ENC 

396 elif patype == 138: 

397 # RFC6113 PA-ENC-TS-ENC 

398 return 54, PA_ENC_TS_ENC 

399 elif isinstance(self.underlayer, KRB_Ticket): 

400 # AS-REP Ticket and TGS-REP Ticket 

401 return 2, EncTicketPart 

402 elif isinstance(self.underlayer, KRB_AS_REP): 

403 # AS-REP encrypted part 

404 return 3, EncASRepPart 

405 elif isinstance(self.underlayer, KRB_KDC_REQ_BODY): 

406 # KDC-REQ enc-authorization-data 

407 return 4, AuthorizationData 

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

409 self.underlayer.underlayer, PADATA 

410 ): 

411 # TGS-REQ PA-TGS-REQ Authenticator 

412 return 7, KRB_Authenticator 

413 elif isinstance(self.underlayer, KRB_TGS_REP): 

414 # TGS-REP encrypted part 

415 return 8, EncTGSRepPart 

416 elif isinstance(self.underlayer, KRB_AP_REQ): 

417 # AP-REQ Authenticator 

418 return 11, KRB_Authenticator 

419 elif isinstance(self.underlayer, KRB_AP_REP): 

420 # AP-REP encrypted part 

421 return 12, EncAPRepPart 

422 elif isinstance(self.underlayer, KRB_PRIV): 

423 # KRB-PRIV encrypted part 

424 return 13, EncKrbPrivPart 

425 elif isinstance(self.underlayer, KRB_CRED): 

426 # KRB-CRED encrypted part 

427 return 14, EncKrbCredPart 

428 elif isinstance(self.underlayer, KrbFastArmoredReq): 

429 # KEY_USAGE_FAST_ENC 

430 return 51, KrbFastReq 

431 elif isinstance(self.underlayer, KrbFastArmoredRep): 

432 # KEY_USAGE_FAST_REP 

433 return 52, KrbFastResponse 

434 raise ValueError( 

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

436 ) 

437 

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

439 """ 

440 Decrypt and return the data contained in cipher. 

441 

442 :param key: the key to use for decryption 

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

444 Guessed otherwise 

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

446 Guessed otherwise (or bytes) 

447 """ 

448 if key_usage_number is None: 

449 key_usage_number, cls = self.get_usage() 

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

451 if cls: 

452 try: 

453 return cls(d) 

454 except BER_Decoding_Error: 

455 if cls == EncASRepPart: 

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

457 # "Compatibility note: Some implementations unconditionally send an 

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

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

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

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

462 try: 

463 res = EncTGSRepPart(d) 

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

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

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

467 log_runtime.warning( 

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

469 ) 

470 return res 

471 except BER_Decoding_Error: 

472 pass 

473 raise 

474 return d 

475 

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

477 """ 

478 Encrypt text and set it into cipher. 

479 

480 :param key: the key to use for encryption 

481 :param text: the bytes value to encode 

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

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

484 Guessed otherwise 

485 """ 

486 if key_usage_number is None: 

487 key_usage_number = self.get_usage()[0] 

488 self.etype = key.etype 

489 self.cipher = ASN1_STRING( 

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

491 ) 

492 

493 

494class EncryptionKey(ASN1_Packet): 

495 ASN1_codec = ASN1_Codecs.BER 

496 ASN1_root = ASN1F_SEQUENCE( 

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

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

499 ) 

500 

501 def toKey(self): 

502 return Key( 

503 etype=self.keytype.val, 

504 key=self.keyvalue.val, 

505 ) 

506 

507 @classmethod 

508 def fromKey(self, key): 

509 return EncryptionKey( 

510 keytype=key.etype, 

511 keyvalue=key.key, 

512 ) 

513 

514 

515class _Checksum_Field(ASN1F_STRING_PacketField): 

516 def m2i(self, pkt, s): 

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

518 if not val[0].val: 

519 return val 

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

521 # Special case per RFC 4121 

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

523 return val 

524 

525 

526class Checksum(ASN1_Packet): 

527 ASN1_codec = ASN1_Codecs.BER 

528 ASN1_root = ASN1F_SEQUENCE( 

529 ASN1F_enum_INTEGER( 

530 "cksumtype", 

531 0, 

532 _KRB_S_TYPES, 

533 explicit_tag=0xA0, 

534 ), 

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

536 ) 

537 

538 def get_usage(self): 

539 """ 

540 Get current key usage number 

541 """ 

542 # RFC 4120 sect 7.5.1 

543 if self.underlayer: 

544 if isinstance(self.underlayer, KRB_Authenticator): 

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

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

547 return 6 

548 elif isinstance(self.underlayer, PA_FOR_USER): 

549 # [MS-SFU] sect 2.2.1 

550 return 17 

551 elif isinstance(self.underlayer, PA_S4U_X509_USER): 

552 # [MS-SFU] sect 2.2.2 

553 return 26 

554 elif isinstance(self.underlayer, AD_KDCIssued): 

555 # AD-KDC-ISSUED checksum 

556 return 19 

557 elif isinstance(self.underlayer, KrbFastArmoredReq): 

558 # KEY_USAGE_FAST_REQ_CHKSUM 

559 return 50 

560 elif isinstance(self.underlayer, KrbFastFinished): 

561 # KEY_USAGE_FAST_FINISHED 

562 return 53 

563 raise ValueError( 

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

565 ) 

566 

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

568 """ 

569 Verify a signature of text using a key. 

570 

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

572 :param text: the bytes to verify 

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

574 Guessed otherwise 

575 """ 

576 if key_usage_number is None: 

577 key_usage_number = self.get_usage() 

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

579 

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

581 """ 

582 Make a signature. 

583 

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

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

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

587 Guessed otherwise 

588 """ 

589 if key_usage_number is None: 

590 key_usage_number = self.get_usage() 

591 self.cksumtype = cksumtype or key.cksumtype 

592 self.checksum = ASN1_STRING( 

593 key.make_checksum( 

594 keyusage=key_usage_number, 

595 text=text, 

596 cksumtype=self.cksumtype, 

597 ) 

598 ) 

599 

600 

601KerberosFlags = ASN1F_FLAGS 

602 

603_ADDR_TYPES = { 

604 # RFC4120 sect 7.5.3 

605 0x02: "IPv4", 

606 0x03: "Directional", 

607 0x05: "ChaosNet", 

608 0x06: "XNS", 

609 0x07: "ISO", 

610 0x0C: "DECNET Phase IV", 

611 0x10: "AppleTalk DDP", 

612 0x14: "NetBios", 

613 0x18: "IPv6", 

614} 

615 

616 

617class HostAddress(ASN1_Packet): 

618 ASN1_codec = ASN1_Codecs.BER 

619 ASN1_root = ASN1F_SEQUENCE( 

620 ASN1F_enum_INTEGER( 

621 "addrType", 

622 0, 

623 _ADDR_TYPES, 

624 explicit_tag=0xA0, 

625 ), 

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

627 ) 

628 

629 

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

631 name, [], HostAddress, **kwargs 

632) 

633 

634 

635_AUTHORIZATIONDATA_VALUES = { 

636 # Filled below 

637} 

638 

639 

640class _AuthorizationData_value_Field(ASN1F_STRING_PacketField): 

641 def m2i(self, pkt, s): 

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

643 if not val[0].val: 

644 return val 

645 if pkt.adType.val in _AUTHORIZATIONDATA_VALUES: 

646 return ( 

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

648 val[1], 

649 ) 

650 return val 

651 

652 

653_AD_TYPES = { 

654 # RFC4120 sect 7.5.4 

655 1: "AD-IF-RELEVANT", 

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

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

658 4: "AD-KDC-ISSUED", 

659 5: "AD-AND-OR", 

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

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

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

663 64: "OSF-DCE", 

664 65: "SESAME", 

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

666 128: "AD-WIN2K-PAC", 

667 129: "AD-ETYPE-NEGOTIATION", 

668 # [MS-KILE] additions 

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

670 142: "KERB-LOCAL", 

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

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

673} 

674 

675 

676class AuthorizationDataItem(ASN1_Packet): 

677 ASN1_codec = ASN1_Codecs.BER 

678 ASN1_root = ASN1F_SEQUENCE( 

679 ASN1F_enum_INTEGER( 

680 "adType", 

681 0, 

682 _AD_TYPES, 

683 explicit_tag=0xA0, 

684 ), 

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

686 ) 

687 

688 

689class AuthorizationData(ASN1_Packet): 

690 ASN1_codec = ASN1_Codecs.BER 

691 ASN1_root = ASN1F_SEQUENCE_OF( 

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

693 ) 

694 

695 def getAuthData(self, adType): 

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

697 

698 

699AD_IF_RELEVANT = AuthorizationData 

700_AUTHORIZATIONDATA_VALUES[1] = AD_IF_RELEVANT 

701 

702 

703class AD_KDCIssued(ASN1_Packet): 

704 ASN1_codec = ASN1_Codecs.BER 

705 ASN1_root = ASN1F_SEQUENCE( 

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

707 ASN1F_optional( 

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

709 ), 

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

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

712 ) 

713 

714 

715_AUTHORIZATIONDATA_VALUES[4] = AD_KDCIssued 

716 

717 

718class AD_AND_OR(ASN1_Packet): 

719 ASN1_codec = ASN1_Codecs.BER 

720 ASN1_root = ASN1F_SEQUENCE( 

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

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

723 ) 

724 

725 

726_AUTHORIZATIONDATA_VALUES[5] = AD_AND_OR 

727 

728ADMANDATORYFORKDC = AuthorizationData 

729_AUTHORIZATIONDATA_VALUES[8] = ADMANDATORYFORKDC 

730 

731 

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

733_PADATA_TYPES = { 

734 1: "PA-TGS-REQ", 

735 2: "PA-ENC-TIMESTAMP", 

736 3: "PA-PW-SALT", 

737 11: "PA-ETYPE-INFO", 

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

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

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

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

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

743 19: "PA-ETYPE-INFO2", 

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

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

746 128: "PA-PAC-REQUEST", 

747 129: "PA-FOR-USER", 

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

749 131: "PA-FOR-CHECK_DUPS", 

750 132: "PA-AS-CHECKSUM", 

751 133: "PA-FX-COOKIE", 

752 134: "PA-AUTHENTICATION-SET", 

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

754 136: "PA-FX-FAST", 

755 137: "PA-FX-ERROR", 

756 138: "PA-ENCRYPTED-CHALLENGE", 

757 141: "PA-OTP-CHALLENGE", 

758 142: "PA-OTP-REQUEST", 

759 143: "PA-OTP-CONFIRM", 

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

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

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

763 147: "PA-PKINIT-KX", 

764 148: "PA-PKU2U-NAME", 

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

766 150: "PA-AS-FRESHNESS", 

767 151: "PA-SPAKE", 

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

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

770 165: "PA-SUPPORTED-ENCTYPES", 

771 166: "PA-EXTENDED-ERROR", 

772 167: "PA-PAC-OPTIONS", 

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

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

775} 

776 

777_PADATA_CLASSES = { 

778 # Filled elsewhere in this file 

779} 

780 

781 

782# RFC4120 

783 

784 

785class _PADATA_value_Field(ASN1F_STRING_PacketField): 

786 """ 

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

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

789 """ 

790 

791 def m2i(self, pkt, s): 

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

793 if pkt.padataType.val in _PADATA_CLASSES: 

794 cls = _PADATA_CLASSES[pkt.padataType.val] 

795 if isinstance(cls, tuple): 

796 parent = pkt.underlayer or pkt.parent 

797 is_reply = False 

798 if parent is not None: 

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

800 is_reply = True 

801 else: 

802 parent = parent.underlayer or parent.parent 

803 is_reply = isinstance(parent, KRB_ERROR) 

804 cls = cls[is_reply] 

805 if not val[0].val: 

806 return val 

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

808 return val 

809 

810 

811class PADATA(ASN1_Packet): 

812 ASN1_codec = ASN1_Codecs.BER 

813 ASN1_root = ASN1F_SEQUENCE( 

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

815 _PADATA_value_Field( 

816 "padataValue", 

817 "", 

818 explicit_tag=0xA2, 

819 ), 

820 ) 

821 

822 

823# RFC 4120 sect 5.2.7.2 

824 

825 

826class PA_ENC_TS_ENC(ASN1_Packet): 

827 ASN1_codec = ASN1_Codecs.BER 

828 ASN1_root = ASN1F_SEQUENCE( 

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

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

831 ) 

832 

833 

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

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

836 

837 

838# RFC 4120 sect 5.2.7.4 

839 

840 

841class ETYPE_INFO_ENTRY(ASN1_Packet): 

842 ASN1_codec = ASN1_Codecs.BER 

843 ASN1_root = ASN1F_SEQUENCE( 

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

845 ASN1F_optional( 

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

847 ), 

848 ) 

849 

850 

851class ETYPE_INFO(ASN1_Packet): 

852 ASN1_codec = ASN1_Codecs.BER 

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

854 

855 

856_PADATA_CLASSES[11] = ETYPE_INFO 

857 

858# RFC 4120 sect 5.2.7.5 

859 

860 

861class ETYPE_INFO_ENTRY2(ASN1_Packet): 

862 ASN1_codec = ASN1_Codecs.BER 

863 ASN1_root = ASN1F_SEQUENCE( 

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

865 ASN1F_optional( 

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

867 ), 

868 ASN1F_optional( 

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

870 ), 

871 ) 

872 

873 

874class ETYPE_INFO2(ASN1_Packet): 

875 ASN1_codec = ASN1_Codecs.BER 

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

877 

878 

879_PADATA_CLASSES[19] = ETYPE_INFO2 

880 

881 

882# RFC8636 - PKINIT Algorithm Agility 

883 

884 

885class TD_CMS_DIGEST_ALGORITHMS(ASN1_Packet): 

886 ASN1_codec = ASN1_Codecs.BER 

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

888 

889 

890_PADATA_CLASSES[111] = TD_CMS_DIGEST_ALGORITHMS 

891 

892 

893# PADATA Extended with RFC6113 

894 

895 

896class PA_AUTHENTICATION_SET_ELEM(ASN1_Packet): 

897 ASN1_codec = ASN1_Codecs.BER 

898 ASN1_root = ASN1F_SEQUENCE( 

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

900 ASN1F_optional( 

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

902 ), 

903 ASN1F_optional( 

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

905 ), 

906 ) 

907 

908 

909class PA_AUTHENTICATION_SET(ASN1_Packet): 

910 ASN1_codec = ASN1_Codecs.BER 

911 ASN1_root = ASN1F_SEQUENCE_OF( 

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

913 ) 

914 

915 

916_PADATA_CLASSES[134] = PA_AUTHENTICATION_SET 

917 

918 

919# [MS-KILE] sect 2.2.3 

920 

921 

922class PA_PAC_REQUEST(ASN1_Packet): 

923 ASN1_codec = ASN1_Codecs.BER 

924 ASN1_root = ASN1F_SEQUENCE( 

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

926 ) 

927 

928 

929_PADATA_CLASSES[128] = PA_PAC_REQUEST 

930 

931 

932# [MS-KILE] sect 2.2.5 

933 

934 

935class LSAP_TOKEN_INFO_INTEGRITY(Packet): 

936 fields_desc = [ 

937 FlagsField( 

938 "Flags", 

939 0, 

940 -32, 

941 { 

942 0x00000001: "UAC-Restricted", 

943 }, 

944 ), 

945 LEIntEnumField( 

946 "TokenIL", 

947 0x00002000, 

948 { 

949 0x00000000: "Untrusted", 

950 0x00001000: "Low", 

951 0x00002000: "Medium", 

952 0x00003000: "High", 

953 0x00004000: "System", 

954 0x00005000: "Protected process", 

955 }, 

956 ), 

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

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

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

960 ] 

961 

962 

963# [MS-KILE] sect 2.2.6 

964 

965 

966class _KerbAdRestrictionEntry_Field(ASN1F_STRING_PacketField): 

967 def m2i(self, pkt, s): 

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

969 if not val[0].val: 

970 return val 

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

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

973 return val 

974 

975 

976class KERB_AD_RESTRICTION_ENTRY(ASN1_Packet): 

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

978 ASN1_codec = ASN1_Codecs.BER 

979 ASN1_root = ASN1F_SEQUENCE( 

980 ASN1F_SEQUENCE( 

981 ASN1F_enum_INTEGER( 

982 "restrictionType", 

983 0, 

984 {0: "LSAP_TOKEN_INFO_INTEGRITY"}, 

985 explicit_tag=0xA0, 

986 ), 

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

988 ) 

989 ) 

990 

991 

992_AUTHORIZATIONDATA_VALUES[141] = KERB_AD_RESTRICTION_ENTRY 

993 

994 

995# [MS-KILE] sect 3.2.5.8 

996 

997 

998class KERB_AUTH_DATA_AP_OPTIONS(Packet): 

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

1000 fields_desc = [ 

1001 FlagsField( 

1002 "apOptions", 

1003 0x4000, 

1004 -32, 

1005 { 

1006 0x4000: "KERB_AP_OPTIONS_CBT", 

1007 0x8000: "KERB_AP_OPTIONS_UNVERIFIED_TARGET_NAME", 

1008 }, 

1009 ), 

1010 ] 

1011 

1012 

1013_AUTHORIZATIONDATA_VALUES[143] = KERB_AUTH_DATA_AP_OPTIONS 

1014 

1015 

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

1017 

1018 

1019class KERB_AUTH_DATA_CLIENT_TARGET(Packet): 

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

1021 fields_desc = [ 

1022 StrFieldUtf16("spn", ""), 

1023 ] 

1024 

1025 

1026_AUTHORIZATIONDATA_VALUES[144] = KERB_AUTH_DATA_CLIENT_TARGET 

1027 

1028 

1029# RFC6806 sect 6 

1030 

1031 

1032class KERB_AD_LOGIN_ALIAS(ASN1_Packet): 

1033 ASN1_codec = ASN1_Codecs.BER 

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

1035 

1036 

1037_AUTHORIZATIONDATA_VALUES[80] = KERB_AD_LOGIN_ALIAS 

1038 

1039 

1040# [MS-KILE] sect 2.2.8 

1041 

1042 

1043class PA_SUPPORTED_ENCTYPES(Packet): 

1044 fields_desc = [ 

1045 FlagsField( 

1046 "flags", 

1047 0, 

1048 -32, 

1049 [ 

1050 "DES-CBC-CRC", 

1051 "DES-CBC-MD5", 

1052 "RC4-HMAC", 

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

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

1055 ] 

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

1057 + [ 

1058 "FAST-supported", 

1059 "Compount-identity-supported", 

1060 "Claims-supported", 

1061 "Resource-SID-compression-disabled", 

1062 ], 

1063 ) 

1064 ] 

1065 

1066 

1067_PADATA_CLASSES[165] = PA_SUPPORTED_ENCTYPES 

1068 

1069# [MS-KILE] sect 2.2.10 

1070 

1071 

1072class PA_PAC_OPTIONS(ASN1_Packet): 

1073 ASN1_codec = ASN1_Codecs.BER 

1074 ASN1_root = ASN1F_SEQUENCE( 

1075 KerberosFlags( 

1076 "options", 

1077 "", 

1078 [ 

1079 "Claims", 

1080 "Branch-Aware", 

1081 "Forward-to-Full-DC", 

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

1083 ], 

1084 explicit_tag=0xA0, 

1085 ) 

1086 ) 

1087 

1088 

1089_PADATA_CLASSES[167] = PA_PAC_OPTIONS 

1090 

1091# [MS-KILE] sect 2.2.11 

1092 

1093 

1094class KERB_KEY_LIST_REQ(ASN1_Packet): 

1095 ASN1_codec = ASN1_Codecs.BER 

1096 ASN1_root = ASN1F_SEQUENCE_OF( 

1097 "keytypes", 

1098 [], 

1099 ASN1F_enum_INTEGER("", 0, _KRB_E_TYPES), 

1100 ) 

1101 

1102 

1103_PADATA_CLASSES[161] = KERB_KEY_LIST_REQ 

1104 

1105# [MS-KILE] sect 2.2.12 

1106 

1107 

1108class KERB_KEY_LIST_REP(ASN1_Packet): 

1109 ASN1_codec = ASN1_Codecs.BER 

1110 ASN1_root = ASN1F_SEQUENCE_OF( 

1111 "keys", 

1112 [], 

1113 ASN1F_PACKET("", None, EncryptionKey), 

1114 ) 

1115 

1116 

1117_PADATA_CLASSES[162] = KERB_KEY_LIST_REP 

1118 

1119# [MS-KILE] sect 2.2.13 

1120 

1121 

1122class KERB_SUPERSEDED_BY_USER(ASN1_Packet): 

1123 ASN1_codec = ASN1_Codecs.BER 

1124 ASN1_root = ASN1F_SEQUENCE( 

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

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

1127 ) 

1128 

1129 

1130_PADATA_CLASSES[170] = KERB_SUPERSEDED_BY_USER 

1131 

1132 

1133# [MS-KILE] sect 2.2.14 

1134 

1135 

1136class KERB_DMSA_KEY_PACKAGE(ASN1_Packet): 

1137 ASN1_codec = ASN1_Codecs.BER 

1138 ASN1_root = ASN1F_SEQUENCE( 

1139 ASN1F_SEQUENCE_OF( 

1140 "currentKeys", 

1141 [], 

1142 ASN1F_PACKET("", None, EncryptionKey), 

1143 explicit_tag=0xA0, 

1144 ), 

1145 ASN1F_optional( 

1146 ASN1F_SEQUENCE_OF( 

1147 "previousKeys", 

1148 [], 

1149 ASN1F_PACKET("", None, EncryptionKey), 

1150 explicit_tag=0xA1, 

1151 ), 

1152 ), 

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

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

1155 ) 

1156 

1157 

1158_PADATA_CLASSES[171] = KERB_DMSA_KEY_PACKAGE 

1159 

1160 

1161# RFC6113 sect 5.4.1 

1162 

1163 

1164class _KrbFastArmor_value_Field(ASN1F_STRING_PacketField): 

1165 def m2i(self, pkt, s): 

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

1167 if not val[0].val: 

1168 return val 

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

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

1171 return val 

1172 

1173 

1174class KrbFastArmor(ASN1_Packet): 

1175 ASN1_codec = ASN1_Codecs.BER 

1176 ASN1_root = ASN1F_SEQUENCE( 

1177 ASN1F_enum_INTEGER( 

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

1179 ), 

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

1181 ) 

1182 

1183 

1184# RFC6113 sect 5.4.2 

1185 

1186 

1187class KrbFastArmoredReq(ASN1_Packet): 

1188 ASN1_codec = ASN1_Codecs.BER 

1189 ASN1_root = ASN1F_SEQUENCE( 

1190 ASN1F_SEQUENCE( 

1191 ASN1F_optional( 

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

1193 ), 

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

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

1196 ) 

1197 ) 

1198 

1199 

1200class PA_FX_FAST_REQUEST(ASN1_Packet): 

1201 ASN1_codec = ASN1_Codecs.BER 

1202 ASN1_root = ASN1F_CHOICE( 

1203 "armoredData", 

1204 ASN1_STRING(""), 

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

1206 ) 

1207 

1208 

1209# RFC6113 sect 5.4.3 

1210 

1211 

1212class KrbFastArmoredRep(ASN1_Packet): 

1213 ASN1_codec = ASN1_Codecs.BER 

1214 ASN1_root = ASN1F_SEQUENCE( 

1215 ASN1F_SEQUENCE( 

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

1217 ) 

1218 ) 

1219 

1220 

1221class PA_FX_FAST_REPLY(ASN1_Packet): 

1222 ASN1_codec = ASN1_Codecs.BER 

1223 ASN1_root = ASN1F_CHOICE( 

1224 "armoredData", 

1225 ASN1_STRING(""), 

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

1227 ) 

1228 

1229 

1230class KrbFastFinished(ASN1_Packet): 

1231 ASN1_codec = ASN1_Codecs.BER 

1232 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

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

1238 ) 

1239 

1240 

1241class KrbFastResponse(ASN1_Packet): 

1242 ASN1_codec = ASN1_Codecs.BER 

1243 ASN1_root = ASN1F_SEQUENCE( 

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

1245 ASN1F_optional( 

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

1247 ), 

1248 ASN1F_optional( 

1249 ASN1F_PACKET( 

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

1251 ) 

1252 ), 

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

1254 ) 

1255 

1256 

1257_PADATA_CLASSES[136] = (PA_FX_FAST_REQUEST, PA_FX_FAST_REPLY) 

1258 

1259 

1260# RFC 4556 - PKINIT 

1261 

1262 

1263# sect 3.2.1 

1264 

1265 

1266class ExternalPrincipalIdentifier(ASN1_Packet): 

1267 ASN1_codec = ASN1_Codecs.BER 

1268 ASN1_root = ASN1F_SEQUENCE( 

1269 ASN1F_optional( 

1270 ASN1F_STRING_ENCAPS( 

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

1272 ), 

1273 ), 

1274 ASN1F_optional( 

1275 ASN1F_STRING_ENCAPS( 

1276 "issuerAndSerialNumber", 

1277 None, 

1278 CMS_IssuerAndSerialNumber, 

1279 implicit_tag=0x81, 

1280 ), 

1281 ), 

1282 ASN1F_optional( 

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

1284 ), 

1285 ) 

1286 

1287 

1288class PA_PK_AS_REQ(ASN1_Packet): 

1289 ASN1_codec = ASN1_Codecs.BER 

1290 ASN1_root = ASN1F_SEQUENCE( 

1291 ASN1F_STRING_ENCAPS( 

1292 "signedAuthpack", 

1293 CMS_ContentInfo(), 

1294 CMS_ContentInfo, 

1295 implicit_tag=0x80, 

1296 ), 

1297 ASN1F_optional( 

1298 ASN1F_SEQUENCE_OF( 

1299 "trustedCertifiers", 

1300 None, 

1301 ExternalPrincipalIdentifier, 

1302 explicit_tag=0xA1, 

1303 ), 

1304 ), 

1305 ASN1F_optional( 

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

1307 ), 

1308 ) 

1309 

1310 

1311_PADATA_CLASSES[16] = PA_PK_AS_REQ 

1312 

1313 

1314# [MS-PKCA] sect 2.2.3 

1315 

1316 

1317class PAChecksum2(ASN1_Packet): 

1318 ASN1_codec = ASN1_Codecs.BER 

1319 ASN1_root = ASN1F_SEQUENCE( 

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

1321 ASN1F_PACKET( 

1322 "algorithmIdentifier", 

1323 X509_AlgorithmIdentifier(), 

1324 X509_AlgorithmIdentifier, 

1325 explicit_tag=0xA1, 

1326 ), 

1327 ) 

1328 

1329 def verify(self, text): 

1330 """ 

1331 Verify a checksum of text. 

1332 

1333 :param text: the bytes to verify 

1334 """ 

1335 # [MS-PKCA] 2.2.3 - PAChecksum2 

1336 

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

1338 oid = self.algorithmIdentifier.algorithm.val 

1339 if oid == "1.3.14.3.2.26": 

1340 hashcls = Hash_SHA 

1341 elif oid == "2.16.840.1.101.3.4.2.1": 

1342 hashcls = Hash_SHA256 

1343 elif oid == "2.16.840.1.101.3.4.2.2": 

1344 hashcls = Hash_SHA384 

1345 elif oid == "2.16.840.1.101.3.4.2.3": 

1346 hashcls = Hash_SHA512 

1347 else: 

1348 raise ValueError("Bad PAChecksum2 checksum !") 

1349 

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

1351 raise ValueError("Bad PAChecksum2 checksum !") 

1352 

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

1354 """ 

1355 Make a checksum. 

1356 

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

1358 """ 

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

1360 if h == "sha1": 

1361 hashcls = Hash_SHA 

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

1363 elif h == "sha256": 

1364 hashcls = Hash_SHA256 

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

1366 elif h == "sha384": 

1367 hashcls = Hash_SHA384 

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

1369 elif h == "sha512": 

1370 hashcls = Hash_SHA512 

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

1372 else: 

1373 raise ValueError("Bad PAChecksum2 checksum !") 

1374 

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

1376 

1377 

1378# still RFC 4556 sect 3.2.1 

1379 

1380 

1381class KRB_PKAuthenticator(ASN1_Packet): 

1382 ASN1_codec = ASN1_Codecs.BER 

1383 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

1387 ASN1F_optional( 

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

1389 ), 

1390 # RFC8070 extension 

1391 ASN1F_optional( 

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

1393 ), 

1394 # [MS-PKCA] sect 2.2.3 

1395 ASN1F_optional( 

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

1397 ), 

1398 ) 

1399 

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

1401 """ 

1402 Populate paChecksum 

1403 """ 

1404 # paChecksum (always sha-1) 

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

1406 

1407 # paChecksum2 

1408 if h != "sha1": 

1409 self.paChecksum2 = PAChecksum2() 

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

1411 

1412 def verify_checksum(self, text): 

1413 """ 

1414 Verify paChecksum and paChecksum2 

1415 """ 

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

1417 raise ValueError("Bad paChecksum checksum !") 

1418 

1419 if self.paChecksum2 is not None: 

1420 self.paChecksum2.verify(text) 

1421 

1422 

1423# RFC8636 sect 6 

1424 

1425 

1426class KDFAlgorithmId(ASN1_Packet): 

1427 ASN1_codec = ASN1_Codecs.BER 

1428 ASN1_root = ASN1F_SEQUENCE( 

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

1430 ) 

1431 

1432 

1433# still RFC 4556 sect 3.2.1 

1434 

1435 

1436class KRB_AuthPack(ASN1_Packet): 

1437 ASN1_codec = ASN1_Codecs.BER 

1438 ASN1_root = ASN1F_SEQUENCE( 

1439 ASN1F_PACKET( 

1440 "pkAuthenticator", 

1441 KRB_PKAuthenticator(), 

1442 KRB_PKAuthenticator, 

1443 explicit_tag=0xA0, 

1444 ), 

1445 ASN1F_optional( 

1446 ASN1F_PACKET( 

1447 "clientPublicValue", 

1448 X509_SubjectPublicKeyInfo(), 

1449 X509_SubjectPublicKeyInfo, 

1450 explicit_tag=0xA1, 

1451 ), 

1452 ), 

1453 ASN1F_optional( 

1454 ASN1F_SEQUENCE_OF( 

1455 "supportedCMSTypes", 

1456 None, 

1457 X509_AlgorithmIdentifier, 

1458 explicit_tag=0xA2, 

1459 ), 

1460 ), 

1461 ASN1F_optional( 

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

1463 ), 

1464 # RFC8636 extension 

1465 ASN1F_optional( 

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

1467 ), 

1468 ) 

1469 

1470 

1471_CMS_ENCAPSULATED["1.3.6.1.5.2.3.1"] = KRB_AuthPack 

1472 

1473# sect 3.2.3 

1474 

1475 

1476class DHRepInfo(ASN1_Packet): 

1477 ASN1_codec = ASN1_Codecs.BER 

1478 ASN1_root = ASN1F_SEQUENCE( 

1479 ASN1F_STRING_ENCAPS( 

1480 "dhSignedData", 

1481 CMS_ContentInfo(), 

1482 CMS_ContentInfo, 

1483 implicit_tag=0x80, 

1484 ), 

1485 ASN1F_optional( 

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

1487 ), 

1488 # RFC8636 extension 

1489 ASN1F_optional( 

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

1491 ), 

1492 ) 

1493 

1494 

1495class EncKeyPack(ASN1_Packet): 

1496 ASN1_codec = ASN1_Codecs.BER 

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

1498 

1499 

1500class PA_PK_AS_REP(ASN1_Packet): 

1501 ASN1_codec = ASN1_Codecs.BER 

1502 ASN1_root = ASN1F_CHOICE( 

1503 "rep", 

1504 ASN1_STRING(""), 

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

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

1507 ) 

1508 

1509 

1510_PADATA_CLASSES[17] = PA_PK_AS_REP 

1511 

1512 

1513class KDCDHKeyInfo(ASN1_Packet): 

1514 ASN1_codec = ASN1_Codecs.BER 

1515 ASN1_root = ASN1F_SEQUENCE( 

1516 ASN1F_BIT_STRING_ENCAPS( 

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

1518 ), 

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

1520 ASN1F_optional( 

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

1522 ), 

1523 ) 

1524 

1525 

1526_CMS_ENCAPSULATED["1.3.6.1.5.2.3.2"] = KDCDHKeyInfo 

1527 

1528# [MS-SFU] 

1529 

1530 

1531# sect 2.2.1 

1532class PA_FOR_USER(ASN1_Packet): 

1533 ASN1_codec = ASN1_Codecs.BER 

1534 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

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

1539 ) 

1540 

1541 

1542_PADATA_CLASSES[129] = PA_FOR_USER 

1543 

1544 

1545# sect 2.2.2 

1546 

1547 

1548class S4UUserID(ASN1_Packet): 

1549 ASN1_codec = ASN1_Codecs.BER 

1550 ASN1_root = ASN1F_SEQUENCE( 

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

1552 ASN1F_optional( 

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

1554 ), 

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

1556 ASN1F_optional( 

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

1558 ), 

1559 ASN1F_optional( 

1560 ASN1F_FLAGS( 

1561 "options", 

1562 "", 

1563 [ 

1564 "reserved", 

1565 "KDC_CHECK_LOGON_HOUR_RESTRICTIONS", 

1566 "USE_REPLY_KEY_USAGE", 

1567 "NT_AUTH_POLICY_NOT_REQUIRED", 

1568 "UNCONDITIONAL_DELEGATION", 

1569 ], 

1570 explicit_tag=0xA4, 

1571 ) 

1572 ), 

1573 ) 

1574 

1575 

1576class PA_S4U_X509_USER(ASN1_Packet): 

1577 ASN1_codec = ASN1_Codecs.BER 

1578 ASN1_root = ASN1F_SEQUENCE( 

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

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

1581 ) 

1582 

1583 

1584_PADATA_CLASSES[130] = PA_S4U_X509_USER 

1585 

1586 

1587# Back to RFC4120 

1588 

1589# sect 5.10 

1590KRB_MSG_TYPES = { 

1591 1: "Ticket", 

1592 2: "Authenticator", 

1593 3: "EncTicketPart", 

1594 10: "AS-REQ", 

1595 11: "AS-REP", 

1596 12: "TGS-REQ", 

1597 13: "TGS-REP", 

1598 14: "AP-REQ", 

1599 15: "AP-REP", 

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

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

1602 20: "KRB-SAFE", 

1603 21: "KRB-PRIV", 

1604 22: "KRB-CRED", 

1605 25: "EncASRepPart", 

1606 26: "EncTGSRepPart", 

1607 27: "EncAPRepPart", 

1608 28: "EncKrbPrivPart", 

1609 29: "EnvKrbCredPart", 

1610 30: "KRB-ERROR", 

1611} 

1612 

1613# sect 5.3 

1614 

1615 

1616class KRB_Ticket(ASN1_Packet): 

1617 ASN1_codec = ASN1_Codecs.BER 

1618 ASN1_root = ASN1F_SEQUENCE( 

1619 ASN1F_SEQUENCE( 

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

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

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

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

1624 ), 

1625 implicit_tag=ASN1_Class_KRB.Ticket, 

1626 ) 

1627 

1628 def getSPN(self): 

1629 return "%s@%s" % ( 

1630 self.sname.toString(), 

1631 self.realm.val.decode(), 

1632 ) 

1633 

1634 

1635class TransitedEncoding(ASN1_Packet): 

1636 ASN1_codec = ASN1_Codecs.BER 

1637 ASN1_root = ASN1F_SEQUENCE( 

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

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

1640 ) 

1641 

1642 

1643_TICKET_FLAGS = [ 

1644 "reserved", 

1645 "forwardable", 

1646 "forwarded", 

1647 "proxiable", 

1648 "proxy", 

1649 "may-postdate", 

1650 "postdated", 

1651 "invalid", 

1652 "renewable", 

1653 "initial", 

1654 "pre-authent", 

1655 "hw-authent", 

1656 "transited-since-policy-checked", 

1657 "ok-as-delegate", 

1658 "unused", 

1659 "canonicalize", # RFC6806 

1660 "anonymous", # RFC6112 + RFC8129 

1661] 

1662 

1663 

1664class EncTicketPart(ASN1_Packet): 

1665 ASN1_codec = ASN1_Codecs.BER 

1666 ASN1_root = ASN1F_SEQUENCE( 

1667 ASN1F_SEQUENCE( 

1668 KerberosFlags( 

1669 "flags", 

1670 "", 

1671 _TICKET_FLAGS, 

1672 explicit_tag=0xA0, 

1673 ), 

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

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

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

1677 ASN1F_PACKET( 

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

1679 ), 

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

1681 ASN1F_optional( 

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

1683 ), 

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

1685 ASN1F_optional( 

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

1687 ), 

1688 ASN1F_optional( 

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

1690 ), 

1691 ASN1F_optional( 

1692 ASN1F_PACKET( 

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

1694 ), 

1695 ), 

1696 ), 

1697 implicit_tag=ASN1_Class_KRB.EncTicketPart, 

1698 ) 

1699 

1700 

1701# sect 5.4.1 

1702 

1703 

1704class KRB_KDC_REQ_BODY(ASN1_Packet): 

1705 ASN1_codec = ASN1_Codecs.BER 

1706 ASN1_root = ASN1F_SEQUENCE( 

1707 KerberosFlags( 

1708 "kdcOptions", 

1709 "", 

1710 [ 

1711 "reserved", 

1712 "forwardable", 

1713 "forwarded", 

1714 "proxiable", 

1715 "proxy", 

1716 "allow-postdate", 

1717 "postdated", 

1718 "unused7", 

1719 "renewable", 

1720 "unused9", 

1721 "unused10", 

1722 "opt-hardware-auth", 

1723 "unused12", 

1724 "unused13", 

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

1726 "canonicalize", # RFC6806 

1727 "request-anonymous", # RFC6112 + RFC8129 

1728 ] 

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

1730 + [ 

1731 "disable-transited-check", 

1732 "renewable-ok", 

1733 "enc-tkt-in-skey", 

1734 "unused29", 

1735 "renew", 

1736 "validate", 

1737 ], 

1738 explicit_tag=0xA0, 

1739 ), 

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

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

1742 ASN1F_optional( 

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

1744 ), 

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

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

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

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

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

1750 ASN1F_optional( 

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

1752 ), 

1753 ASN1F_optional( 

1754 ASN1F_PACKET( 

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

1756 ), 

1757 ), 

1758 ASN1F_optional( 

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

1760 ), 

1761 ) 

1762 

1763 

1764KRB_KDC_REQ = ASN1F_SEQUENCE( 

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

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

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

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

1769) 

1770 

1771 

1772class KrbFastReq(ASN1_Packet): 

1773 # RFC6113 sect 5.4.2 

1774 ASN1_codec = ASN1_Codecs.BER 

1775 ASN1_root = ASN1F_SEQUENCE( 

1776 KerberosFlags( 

1777 "fastOptions", 

1778 "", 

1779 [ 

1780 "RESERVED", 

1781 "hide-client-names", 

1782 ] 

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

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

1785 explicit_tag=0xA0, 

1786 ), 

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

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

1789 ) 

1790 

1791 

1792class KRB_AS_REQ(ASN1_Packet): 

1793 ASN1_codec = ASN1_Codecs.BER 

1794 ASN1_root = ASN1F_SEQUENCE( 

1795 KRB_KDC_REQ, 

1796 implicit_tag=ASN1_Class_KRB.AS_REQ, 

1797 ) 

1798 

1799 

1800class KRB_TGS_REQ(ASN1_Packet): 

1801 ASN1_codec = ASN1_Codecs.BER 

1802 ASN1_root = ASN1F_SEQUENCE( 

1803 KRB_KDC_REQ, 

1804 implicit_tag=ASN1_Class_KRB.TGS_REQ, 

1805 ) 

1806 msgType = ASN1_INTEGER(12) 

1807 

1808 

1809# sect 5.4.2 

1810 

1811KRB_KDC_REP = ASN1F_SEQUENCE( 

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

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

1814 ASN1F_optional( 

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

1816 ), 

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

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

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

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

1821) 

1822 

1823 

1824class KRB_AS_REP(ASN1_Packet): 

1825 ASN1_codec = ASN1_Codecs.BER 

1826 ASN1_root = ASN1F_SEQUENCE( 

1827 KRB_KDC_REP, 

1828 implicit_tag=ASN1_Class_KRB.AS_REP, 

1829 ) 

1830 

1831 def getUPN(self): 

1832 return "%s@%s" % ( 

1833 self.cname.toString(), 

1834 self.crealm.val.decode(), 

1835 ) 

1836 

1837 

1838class KRB_TGS_REP(ASN1_Packet): 

1839 ASN1_codec = ASN1_Codecs.BER 

1840 ASN1_root = ASN1F_SEQUENCE( 

1841 KRB_KDC_REP, 

1842 implicit_tag=ASN1_Class_KRB.TGS_REP, 

1843 ) 

1844 

1845 def getUPN(self): 

1846 return "%s@%s" % ( 

1847 self.cname.toString(), 

1848 self.crealm.val.decode(), 

1849 ) 

1850 

1851 

1852class LastReqItem(ASN1_Packet): 

1853 ASN1_codec = ASN1_Codecs.BER 

1854 ASN1_root = ASN1F_SEQUENCE( 

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

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

1857 ) 

1858 

1859 

1860EncKDCRepPart = ASN1F_SEQUENCE( 

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

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

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

1864 ASN1F_optional( 

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

1866 ), 

1867 KerberosFlags( 

1868 "flags", 

1869 "", 

1870 _TICKET_FLAGS, 

1871 explicit_tag=0xA4, 

1872 ), 

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

1874 ASN1F_optional( 

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

1876 ), 

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

1878 ASN1F_optional( 

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

1880 ), 

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

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

1883 ASN1F_optional( 

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

1885 ), 

1886 # RFC6806 sect 11 

1887 ASN1F_optional( 

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

1889 ), 

1890) 

1891 

1892 

1893class EncASRepPart(ASN1_Packet): 

1894 ASN1_codec = ASN1_Codecs.BER 

1895 ASN1_root = ASN1F_SEQUENCE( 

1896 EncKDCRepPart, 

1897 implicit_tag=ASN1_Class_KRB.EncASRepPart, 

1898 ) 

1899 

1900 

1901class EncTGSRepPart(ASN1_Packet): 

1902 ASN1_codec = ASN1_Codecs.BER 

1903 ASN1_root = ASN1F_SEQUENCE( 

1904 EncKDCRepPart, 

1905 implicit_tag=ASN1_Class_KRB.EncTGSRepPart, 

1906 ) 

1907 

1908 

1909# sect 5.5.1 

1910 

1911 

1912class KRB_AP_REQ(ASN1_Packet): 

1913 ASN1_codec = ASN1_Codecs.BER 

1914 ASN1_root = ASN1F_SEQUENCE( 

1915 ASN1F_SEQUENCE( 

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

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

1918 KerberosFlags( 

1919 "apOptions", 

1920 "", 

1921 [ 

1922 "reserved", 

1923 "use-session-key", 

1924 "mutual-required", 

1925 ], 

1926 explicit_tag=0xA2, 

1927 ), 

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

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

1930 ), 

1931 implicit_tag=ASN1_Class_KRB.AP_REQ, 

1932 ) 

1933 

1934 

1935_PADATA_CLASSES[1] = KRB_AP_REQ 

1936 

1937 

1938class KRB_Authenticator(ASN1_Packet): 

1939 ASN1_codec = ASN1_Codecs.BER 

1940 ASN1_root = ASN1F_SEQUENCE( 

1941 ASN1F_SEQUENCE( 

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

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

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

1945 ASN1F_optional( 

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

1947 ), 

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

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

1950 ASN1F_optional( 

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

1952 ), 

1953 ASN1F_optional( 

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

1955 ), 

1956 ASN1F_optional( 

1957 ASN1F_PACKET( 

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

1959 ), 

1960 ), 

1961 ), 

1962 implicit_tag=ASN1_Class_KRB.Authenticator, 

1963 ) 

1964 

1965 

1966# sect 5.5.2 

1967 

1968 

1969class KRB_AP_REP(ASN1_Packet): 

1970 ASN1_codec = ASN1_Codecs.BER 

1971 ASN1_root = ASN1F_SEQUENCE( 

1972 ASN1F_SEQUENCE( 

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

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

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

1976 ), 

1977 implicit_tag=ASN1_Class_KRB.AP_REP, 

1978 ) 

1979 

1980 

1981class EncAPRepPart(ASN1_Packet): 

1982 ASN1_codec = ASN1_Codecs.BER 

1983 ASN1_root = ASN1F_SEQUENCE( 

1984 ASN1F_SEQUENCE( 

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

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

1987 ASN1F_optional( 

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

1989 ), 

1990 ASN1F_optional( 

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

1992 ), 

1993 ), 

1994 implicit_tag=ASN1_Class_KRB.EncAPRepPart, 

1995 ) 

1996 

1997 

1998# sect 5.7 

1999 

2000 

2001class KRB_PRIV(ASN1_Packet): 

2002 ASN1_codec = ASN1_Codecs.BER 

2003 ASN1_root = ASN1F_SEQUENCE( 

2004 ASN1F_SEQUENCE( 

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

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

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

2008 ), 

2009 implicit_tag=ASN1_Class_KRB.PRIV, 

2010 ) 

2011 

2012 

2013class EncKrbPrivPart(ASN1_Packet): 

2014 ASN1_codec = ASN1_Codecs.BER 

2015 ASN1_root = ASN1F_SEQUENCE( 

2016 ASN1F_SEQUENCE( 

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

2018 ASN1F_optional( 

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

2020 ), 

2021 ASN1F_optional( 

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

2023 ), 

2024 ASN1F_optional( 

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

2026 ), 

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

2028 ASN1F_optional( 

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

2030 ), 

2031 ), 

2032 implicit_tag=ASN1_Class_KRB.EncKrbPrivPart, 

2033 ) 

2034 

2035 

2036# sect 5.8 

2037 

2038 

2039class KRB_CRED(ASN1_Packet): 

2040 ASN1_codec = ASN1_Codecs.BER 

2041 ASN1_root = ASN1F_SEQUENCE( 

2042 ASN1F_SEQUENCE( 

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

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

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

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

2047 ), 

2048 implicit_tag=ASN1_Class_KRB.CRED, 

2049 ) 

2050 

2051 

2052class KrbCredInfo(ASN1_Packet): 

2053 ASN1_codec = ASN1_Codecs.BER 

2054 ASN1_root = ASN1F_SEQUENCE( 

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

2056 ASN1F_optional( 

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

2058 ), 

2059 ASN1F_optional( 

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

2061 ), 

2062 ASN1F_optional( 

2063 KerberosFlags( 

2064 "flags", 

2065 None, 

2066 _TICKET_FLAGS, 

2067 explicit_tag=0xA3, 

2068 ), 

2069 ), 

2070 ASN1F_optional( 

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

2072 ), 

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

2074 ASN1F_optional( 

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

2076 ), 

2077 ASN1F_optional( 

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

2079 ), 

2080 ASN1F_optional( 

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

2082 ), 

2083 ASN1F_optional( 

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

2085 ), 

2086 ASN1F_optional( 

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

2088 ), 

2089 ) 

2090 

2091 

2092class EncKrbCredPart(ASN1_Packet): 

2093 ASN1_codec = ASN1_Codecs.BER 

2094 ASN1_root = ASN1F_SEQUENCE( 

2095 ASN1F_SEQUENCE( 

2096 ASN1F_SEQUENCE_OF( 

2097 "ticketInfo", 

2098 [KrbCredInfo()], 

2099 KrbCredInfo, 

2100 explicit_tag=0xA0, 

2101 ), 

2102 ASN1F_optional( 

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

2104 ), 

2105 ASN1F_optional( 

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

2107 ), 

2108 ASN1F_optional( 

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

2110 ), 

2111 ASN1F_optional( 

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

2113 ), 

2114 ASN1F_optional( 

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

2116 ), 

2117 ), 

2118 implicit_tag=ASN1_Class_KRB.EncKrbCredPart, 

2119 ) 

2120 

2121 

2122# sect 5.9.1 

2123 

2124 

2125class MethodData(ASN1_Packet): 

2126 ASN1_codec = ASN1_Codecs.BER 

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

2128 

2129 

2130class _KRBERROR_data_Field(ASN1F_STRING_PacketField): 

2131 def m2i(self, pkt, s): 

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

2133 if not val[0].val: 

2134 return val 

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

2136 # 14: KDC_ERR_ETYPE_NOSUPP 

2137 # 24: KDC_ERR_PREAUTH_FAILED 

2138 # 25: KDC_ERR_PREAUTH_REQUIRED 

2139 # 36: KRB_AP_ERR_BADMATCH 

2140 # 80: KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED 

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

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

2143 # 6: KDC_ERR_C_PRINCIPAL_UNKNOWN 

2144 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

2145 # 12: KDC_ERR_POLICY 

2146 # 13: KDC_ERR_BADOPTION 

2147 # 18: KDC_ERR_CLIENT_REVOKED 

2148 # 23: KDC_ERR_KEY_EXPIRED 

2149 # 29: KDC_ERR_SVC_UNAVAILABLE 

2150 # 32: KRB_AP_ERR_TKT_EXPIRED 

2151 # 41: KRB_AP_ERR_MODIFIED 

2152 # 60: KRB_ERR_GENERIC 

2153 # 62: KERB_ERR_TYPE_EXTENDED 

2154 try: 

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

2156 except BER_Decoding_Error: 

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

2158 # Some types can also happen in FAST sessions 

2159 # 18: KDC_ERR_CLIENT_REVOKED 

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

2161 elif pkt.errorCode.val == 7: 

2162 # This looks like an undocumented structure. 

2163 # 7: KDC_ERR_S_PRINCIPAL_UNKNOWN 

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

2165 raise 

2166 elif pkt.errorCode.val == 69: 

2167 # KRB_AP_ERR_USER_TO_USER_REQUIRED 

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

2169 return val 

2170 

2171 

2172class KRB_ERROR(ASN1_Packet): 

2173 ASN1_codec = ASN1_Codecs.BER 

2174 ASN1_root = ASN1F_SEQUENCE( 

2175 ASN1F_SEQUENCE( 

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

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

2178 ASN1F_optional( 

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

2180 ), 

2181 ASN1F_optional( 

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

2183 ), 

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

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

2186 ASN1F_enum_INTEGER( 

2187 "errorCode", 

2188 0, 

2189 { 

2190 # RFC4120 sect 7.5.9 

2191 0: "KDC_ERR_NONE", 

2192 1: "KDC_ERR_NAME_EXP", 

2193 2: "KDC_ERR_SERVICE_EXP", 

2194 3: "KDC_ERR_BAD_PVNO", 

2195 4: "KDC_ERR_C_OLD_MAST_KVNO", 

2196 5: "KDC_ERR_S_OLD_MAST_KVNO", 

2197 6: "KDC_ERR_C_PRINCIPAL_UNKNOWN", 

2198 7: "KDC_ERR_S_PRINCIPAL_UNKNOWN", 

2199 8: "KDC_ERR_PRINCIPAL_NOT_UNIQUE", 

2200 9: "KDC_ERR_NULL_KEY", 

2201 10: "KDC_ERR_CANNOT_POSTDATE", 

2202 11: "KDC_ERR_NEVER_VALID", 

2203 12: "KDC_ERR_POLICY", 

2204 13: "KDC_ERR_BADOPTION", 

2205 14: "KDC_ERR_ETYPE_NOSUPP", 

2206 15: "KDC_ERR_SUMTYPE_NOSUPP", 

2207 16: "KDC_ERR_PADATA_TYPE_NOSUPP", 

2208 17: "KDC_ERR_TRTYPE_NOSUPP", 

2209 18: "KDC_ERR_CLIENT_REVOKED", 

2210 19: "KDC_ERR_SERVICE_REVOKED", 

2211 20: "KDC_ERR_TGT_REVOKED", 

2212 21: "KDC_ERR_CLIENT_NOTYET", 

2213 22: "KDC_ERR_SERVICE_NOTYET", 

2214 23: "KDC_ERR_KEY_EXPIRED", 

2215 24: "KDC_ERR_PREAUTH_FAILED", 

2216 25: "KDC_ERR_PREAUTH_REQUIRED", 

2217 26: "KDC_ERR_SERVER_NOMATCH", 

2218 27: "KDC_ERR_MUST_USE_USER2USER", 

2219 28: "KDC_ERR_PATH_NOT_ACCEPTED", 

2220 29: "KDC_ERR_SVC_UNAVAILABLE", 

2221 31: "KRB_AP_ERR_BAD_INTEGRITY", 

2222 32: "KRB_AP_ERR_TKT_EXPIRED", 

2223 33: "KRB_AP_ERR_TKT_NYV", 

2224 34: "KRB_AP_ERR_REPEAT", 

2225 35: "KRB_AP_ERR_NOT_US", 

2226 36: "KRB_AP_ERR_BADMATCH", 

2227 37: "KRB_AP_ERR_SKEW", 

2228 38: "KRB_AP_ERR_BADADDR", 

2229 39: "KRB_AP_ERR_BADVERSION", 

2230 40: "KRB_AP_ERR_MSG_TYPE", 

2231 41: "KRB_AP_ERR_MODIFIED", 

2232 42: "KRB_AP_ERR_BADORDER", 

2233 44: "KRB_AP_ERR_BADKEYVER", 

2234 45: "KRB_AP_ERR_NOKEY", 

2235 46: "KRB_AP_ERR_MUT_FAIL", 

2236 47: "KRB_AP_ERR_BADDIRECTION", 

2237 48: "KRB_AP_ERR_METHOD", 

2238 49: "KRB_AP_ERR_BADSEQ", 

2239 50: "KRB_AP_ERR_INAPP_CKSUM", 

2240 51: "KRB_AP_PATH_NOT_ACCEPTED", 

2241 52: "KRB_ERR_RESPONSE_TOO_BIG", 

2242 60: "KRB_ERR_GENERIC", 

2243 61: "KRB_ERR_FIELD_TOOLONG", 

2244 # RFC4556 

2245 62: "KDC_ERR_CLIENT_NOT_TRUSTED", 

2246 63: "KDC_ERR_KDC_NOT_TRUSTED", 

2247 64: "KDC_ERR_INVALID_SIG", 

2248 65: "KDC_ERR_KEY_TOO_WEAK", 

2249 66: "KDC_ERR_CERTIFICATE_MISMATCH", 

2250 67: "KRB_AP_ERR_NO_TGT", 

2251 68: "KDC_ERR_WRONG_REALM", 

2252 69: "KRB_AP_ERR_USER_TO_USER_REQUIRED", 

2253 70: "KDC_ERR_CANT_VERIFY_CERTIFICATE", 

2254 71: "KDC_ERR_INVALID_CERTIFICATE", 

2255 72: "KDC_ERR_REVOKED_CERTIFICATE", 

2256 73: "KDC_ERR_REVOCATION_STATUS_UNKNOWN", 

2257 74: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE", 

2258 75: "KDC_ERR_CLIENT_NAME_MISMATCH", 

2259 76: "KDC_ERR_KDC_NAME_MISMATCH", 

2260 77: "KDC_ERR_INCONSISTENT_KEY_PURPOSE", 

2261 78: "KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED", 

2262 79: "KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED", 

2263 80: "KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED", 

2264 81: "KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED", 

2265 # draft-ietf-kitten-iakerb 

2266 85: "KRB_AP_ERR_IAKERB_KDC_NOT_FOUND", 

2267 86: "KRB_AP_ERR_IAKERB_KDC_NO_RESPONSE", 

2268 # RFC6113 

2269 90: "KDC_ERR_PREAUTH_EXPIRED", 

2270 91: "KDC_ERR_MORE_PREAUTH_DATA_REQUIRED", 

2271 92: "KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET", 

2272 93: "KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS", 

2273 # RFC8636 

2274 100: "KDC_ERR_NO_ACCEPTABLE_KDF", 

2275 }, 

2276 explicit_tag=0xA6, 

2277 ), 

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

2279 ASN1F_optional( 

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

2281 ), 

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

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

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

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

2286 ), 

2287 implicit_tag=ASN1_Class_KRB.ERROR, 

2288 ) 

2289 

2290 def getSPN(self): 

2291 return "%s@%s" % ( 

2292 self.sname.toString(), 

2293 self.realm.val.decode(), 

2294 ) 

2295 

2296 

2297# PA-FX-ERROR 

2298_PADATA_CLASSES[137] = KRB_ERROR 

2299 

2300 

2301# [MS-KILE] sect 2.2.1 

2302 

2303 

2304class KERB_EXT_ERROR(Packet): 

2305 fields_desc = [ 

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

2307 XLEIntField("reserved", 0), 

2308 XLEIntField("flags", 0x00000001), 

2309 ] 

2310 

2311 

2312class KERB_EXT_ERROR_NTSTATUS(Packet): 

2313 fields_desc = [ 

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

2315 ] 

2316 

2317 

2318# [MS-KILE] sect 2.2.2 

2319 

2320 

2321class _Error_Field(ASN1F_STRING_PacketField): 

2322 def m2i(self, pkt, s): 

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

2324 if not val[0].val: 

2325 return val 

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

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

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

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

2330 return val 

2331 

2332 

2333class KERB_ERROR_DATA(ASN1_Packet): 

2334 ASN1_codec = ASN1_Codecs.BER 

2335 ASN1_root = ASN1F_SEQUENCE( 

2336 ASN1F_enum_INTEGER( 

2337 "dataType", 

2338 2, 

2339 { 

2340 1: "KERB_AP_ERR_TYPE_NTSTATUS", # from the wdk 

2341 2: "KERB_AP_ERR_TYPE_SKEW_RECOVERY", 

2342 3: "KERB_ERR_TYPE_EXTENDED", 

2343 }, 

2344 explicit_tag=0xA1, 

2345 ), 

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

2347 ) 

2348 

2349 

2350# This looks like an undocumented structure. 

2351 

2352 

2353class KERB_ERROR_UNK(ASN1_Packet): 

2354 ASN1_codec = ASN1_Codecs.BER 

2355 ASN1_root = ASN1F_SEQUENCE( 

2356 ASN1F_SEQUENCE( 

2357 ASN1F_enum_INTEGER( 

2358 "dataType", 

2359 0, 

2360 { 

2361 -128: "KDC_ERR_MUST_USE_USER2USER", 

2362 }, 

2363 explicit_tag=0xA0, 

2364 ), 

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

2366 ) 

2367 ) 

2368 

2369 

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

2371 

2372 

2373class KRB_TGT_REQ(ASN1_Packet): 

2374 ASN1_codec = ASN1_Codecs.BER 

2375 ASN1_root = ASN1F_SEQUENCE( 

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

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

2378 ASN1F_optional( 

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

2380 ), 

2381 ASN1F_optional( 

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

2383 ), 

2384 ) 

2385 

2386 

2387class KRB_TGT_REP(ASN1_Packet): 

2388 ASN1_codec = ASN1_Codecs.BER 

2389 ASN1_root = ASN1F_SEQUENCE( 

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

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

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

2393 ) 

2394 

2395 

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

2397 

2398 

2399class KRB_FINISHED(ASN1_Packet): 

2400 ASN1_codec = ASN1_Codecs.BER 

2401 ASN1_root = ASN1F_SEQUENCE( 

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

2403 ) 

2404 

2405 

2406# RFC 6542 sect 3.1 

2407 

2408 

2409class KRB_GSS_EXT(Packet): 

2410 fields_desc = [ 

2411 IntEnumField( 

2412 "type", 

2413 0, 

2414 { 

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

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

2417 0x00000001: "GSS_EXTS_IAKERB_FINISHED", # not standard 

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

2419 }, 

2420 ), 

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

2422 MultipleTypeField( 

2423 [ 

2424 ( 

2425 PacketField("data", KRB_FINISHED(), KRB_FINISHED), 

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

2427 ), 

2428 ], 

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

2430 ), 

2431 ] 

2432 

2433 

2434# RFC 4121 sect 4.1.1 

2435 

2436 

2437class KRB_AuthenticatorChecksum(Packet): 

2438 fields_desc = [ 

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

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

2441 FlagsField( 

2442 "Flags", 

2443 0, 

2444 -32, 

2445 { 

2446 0x01: "GSS_C_DELEG_FLAG", 

2447 0x02: "GSS_C_MUTUAL_FLAG", 

2448 0x04: "GSS_C_REPLAY_FLAG", 

2449 0x08: "GSS_C_SEQUENCE_FLAG", 

2450 0x10: "GSS_C_CONF_FLAG", # confidentiality 

2451 0x20: "GSS_C_INTEG_FLAG", # integrity 

2452 # RFC4757 

2453 0x1000: "GSS_C_DCE_STYLE", 

2454 0x2000: "GSS_C_IDENTIFY_FLAG", 

2455 0x4000: "GSS_C_EXTENDED_ERROR_FLAG", 

2456 }, 

2457 ), 

2458 ConditionalField( 

2459 LEShortField("DlgOpt", 1), 

2460 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2461 ), 

2462 ConditionalField( 

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

2464 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2465 ), 

2466 ConditionalField( 

2467 PacketLenField( 

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

2469 ), 

2470 lambda pkt: pkt.Flags.GSS_C_DELEG_FLAG, 

2471 ), 

2472 # Extensions: RFC 6542 sect 3.1 

2473 PacketListField("Exts", KRB_GSS_EXT(), KRB_GSS_EXT), 

2474 ] 

2475 

2476 

2477# Kerberos V5 GSS-API - RFC1964 and RFC4121 

2478 

2479_TOK_IDS = { 

2480 # RFC 1964 

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

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

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

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

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

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

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

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

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

2490 # RFC 4121 

2491 b"\x04\x04": "GSS_GetMIC", 

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

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

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

2495} 

2496_SGN_ALGS = { 

2497 0x00: "DES MAC MD5", 

2498 0x01: "MD2.5", 

2499 0x02: "DES MAC", 

2500 # RFC 4757 

2501 0x11: "HMAC", 

2502} 

2503_SEAL_ALGS = { 

2504 0: "DES", 

2505 0xFFFF: "none", 

2506 # RFC 4757 

2507 0x10: "RC4", 

2508} 

2509 

2510 

2511# RFC 1964 - sect 1.1 

2512 

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

2514_InitialContextTokens = {} # filled below 

2515 

2516 

2517class KRB_InnerToken(Packet): 

2518 name = "Kerberos v5 InnerToken" 

2519 fields_desc = [ 

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

2521 PacketField( 

2522 "root", 

2523 KRB_AP_REQ(), 

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

2525 ), 

2526 ] 

2527 

2528 def mysummary(self): 

2529 return self.sprintf( 

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

2531 ) 

2532 

2533 def guess_payload_class(self, payload): 

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

2535 return conf.padding_layer 

2536 return Kerberos 

2537 

2538 @classmethod 

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

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

2541 # Older RFC1964 variants of the token have KRB_GSSAPI_Token wrapper 

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

2543 return KRB_GSSAPI_Token 

2544 return cls 

2545 

2546 

2547# RFC 4121 - sect 4.1 

2548 

2549 

2550class KRB_GSSAPI_Token(GSSAPI_BLOB): 

2551 name = "Kerberos GSSAPI-Token" 

2552 ASN1_codec = ASN1_Codecs.BER 

2553 ASN1_root = ASN1F_SEQUENCE( 

2554 ASN1F_OID("MechType", "1.2.840.113554.1.2.2"), 

2555 ASN1F_PACKET( 

2556 "innerToken", 

2557 KRB_InnerToken(), 

2558 KRB_InnerToken, 

2559 implicit_tag=0x0, 

2560 ), 

2561 implicit_tag=ASN1_Class_KRB.Token, 

2562 ) 

2563 

2564 

2565# RFC 1964 - sect 1.2.1 

2566 

2567 

2568class KRB_GSS_MIC_RFC1964(Packet): 

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

2570 fields_desc = [ 

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

2572 XLEIntField("Filler", 0xFFFFFFFF), 

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

2574 PadField( # sect 1.2.2.3 

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

2576 align=8, 

2577 padwith=b"\x04", 

2578 ), 

2579 ] 

2580 

2581 def default_payload_class(self, payload): 

2582 return conf.padding_layer 

2583 

2584 

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

2586 

2587# RFC 1964 - sect 1.2.2 

2588 

2589 

2590class KRB_GSS_Wrap_RFC1964(Packet): 

2591 name = "Kerberos v5 GSS_Wrap (RFC1964)" 

2592 fields_desc = [ 

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

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

2595 XLEShortField("Filler", 0xFFFF), 

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

2597 PadField( # sect 1.2.2.3 

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

2599 align=8, 

2600 padwith=b"\x04", 

2601 ), 

2602 # sect 1.2.2.3 

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

2604 ] 

2605 

2606 def default_payload_class(self, payload): 

2607 return conf.padding_layer 

2608 

2609 

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

2611 

2612 

2613# RFC 1964 - sect 1.2.2 

2614 

2615 

2616class KRB_GSS_Delete_sec_context_RFC1964(Packet): 

2617 name = "Kerberos v5 GSS_Delete_sec_context (RFC1964)" 

2618 fields_desc = KRB_GSS_MIC_RFC1964.fields_desc 

2619 

2620 

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

2622 

2623 

2624# RFC 4121 - sect 4.2.2 

2625_KRB5_GSS_Flags = [ 

2626 "SentByAcceptor", 

2627 "Sealed", 

2628 "AcceptorSubkey", 

2629] 

2630 

2631 

2632# RFC 4121 - sect 4.2.6.1 

2633 

2634 

2635class KRB_GSS_MIC(Packet): 

2636 name = "Kerberos v5 MIC Token" 

2637 fields_desc = [ 

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

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

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

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

2642 ] 

2643 

2644 def default_payload_class(self, payload): 

2645 return conf.padding_layer 

2646 

2647 

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

2649 

2650 

2651# RFC 4121 - sect 4.2.6.2 

2652 

2653 

2654class KRB_GSS_Wrap(Packet): 

2655 name = "Kerberos v5 Wrap Token" 

2656 fields_desc = [ 

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

2658 XByteField("Filler", 0xFF), 

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

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

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

2662 MultipleTypeField( 

2663 [ 

2664 ( 

2665 XStrField("Data", b""), 

2666 lambda pkt: pkt.Flags.Sealed, 

2667 ) 

2668 ], 

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

2670 ), 

2671 ] 

2672 

2673 def default_payload_class(self, payload): 

2674 return conf.padding_layer 

2675 

2676 

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

2678 

2679 

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

2681 

2682 

2683class IAKERB_HEADER(ASN1_Packet): 

2684 ASN1_codec = ASN1_Codecs.BER 

2685 ASN1_root = ASN1F_SEQUENCE( 

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

2687 ASN1F_optional( 

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

2689 ), 

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

2691 # (but I've sent an email to dochelp for questions) 

2692 ASN1F_optional( 

2693 ASN1F_FLAGS( 

2694 "dclocatorHint", 

2695 "", 

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

2697 explicit_tag=0xA3, 

2698 ) 

2699 ), 

2700 ) 

2701 

2702 def default_payload_class(self, payload): 

2703 return conf.padding_layer 

2704 

2705 

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

2707 

2708 

2709# Register for GSSAPI 

2710 

2711# Kerberos 5 

2712_GSSAPI_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2713_GSSAPI_SIGNATURE_OIDS["1.2.840.113554.1.2.2"] = KRB_InnerToken 

2714# Kerberos 5 - U2U 

2715_GSSAPI_OIDS["1.2.840.113554.1.2.2.3"] = KRB_InnerToken 

2716# Kerberos 5 - IAKERB 

2717_GSSAPI_OIDS["1.3.6.1.5.2.5"] = KRB_InnerToken 

2718 

2719 

2720# Entry class 

2721 

2722# RFC4120 sect 5.10 

2723 

2724 

2725class Kerberos(ASN1_Packet): 

2726 ASN1_codec = ASN1_Codecs.BER 

2727 ASN1_root = ASN1F_CHOICE( 

2728 "root", 

2729 None, 

2730 # RFC4120 

2731 KRB_GSSAPI_Token, # [APPLICATION 0] 

2732 KRB_Ticket, # [APPLICATION 1] 

2733 KRB_Authenticator, # [APPLICATION 2] 

2734 KRB_AS_REQ, # [APPLICATION 10] 

2735 KRB_AS_REP, # [APPLICATION 11] 

2736 KRB_TGS_REQ, # [APPLICATION 12] 

2737 KRB_TGS_REP, # [APPLICATION 13] 

2738 KRB_AP_REQ, # [APPLICATION 14] 

2739 KRB_AP_REP, # [APPLICATION 15] 

2740 # RFC4120 

2741 KRB_ERROR, # [APPLICATION 30] 

2742 ) 

2743 

2744 def mysummary(self): 

2745 return self.root.summary() 

2746 

2747 

2748bind_bottom_up(UDP, Kerberos, sport=88) 

2749bind_bottom_up(UDP, Kerberos, dport=88) 

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

2751 

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

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

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

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

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

2757 

2758 

2759# RFC4120 sect 7.2.2 

2760 

2761 

2762class KerberosTCPHeader(Packet): 

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

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

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

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

2767 

2768 @classmethod 

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

2770 if len(data) < 4: 

2771 return None 

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

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

2774 return cls(data) 

2775 

2776 

2777bind_layers(KerberosTCPHeader, Kerberos) 

2778 

2779bind_bottom_up(TCP, KerberosTCPHeader, sport=88) 

2780bind_layers(TCP, KerberosTCPHeader, dport=88) 

2781 

2782 

2783# RFC3244 sect 2 

2784 

2785 

2786class KPASSWD_REQ(Packet): 

2787 fields_desc = [ 

2788 ShortField("len", None), 

2789 ShortField("pvno", 0xFF80), 

2790 ShortField("apreqlen", None), 

2791 PacketLenField( 

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

2793 ), 

2794 ConditionalField( 

2795 PacketLenField( 

2796 "krbpriv", 

2797 KRB_PRIV(), 

2798 KRB_PRIV, 

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

2800 ), 

2801 lambda pkt: pkt.apreqlen != 0, 

2802 ), 

2803 ConditionalField( 

2804 PacketLenField( 

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

2806 ), 

2807 lambda pkt: pkt.apreqlen == 0, 

2808 ), 

2809 ] 

2810 

2811 def post_build(self, p, pay): 

2812 if self.len is None: 

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

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

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

2816 return p + pay 

2817 

2818 

2819class ChangePasswdData(ASN1_Packet): 

2820 ASN1_codec = ASN1_Codecs.BER 

2821 ASN1_root = ASN1F_SEQUENCE( 

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

2823 ASN1F_optional( 

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

2825 ), 

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

2827 ) 

2828 

2829 

2830class KPASSWD_REP(Packet): 

2831 fields_desc = [ 

2832 ShortField("len", None), 

2833 ShortField("pvno", 0x0001), 

2834 ShortField("apreplen", None), 

2835 PacketLenField( 

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

2837 ), 

2838 ConditionalField( 

2839 PacketLenField( 

2840 "krbpriv", 

2841 KRB_PRIV(), 

2842 KRB_PRIV, 

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

2844 ), 

2845 lambda pkt: pkt.apreplen != 0, 

2846 ), 

2847 ConditionalField( 

2848 PacketLenField( 

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

2850 ), 

2851 lambda pkt: pkt.apreplen == 0, 

2852 ), 

2853 ] 

2854 

2855 def post_build(self, p, pay): 

2856 if self.len is None: 

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

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

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

2860 return p + pay 

2861 

2862 def answers(self, other): 

2863 return isinstance(other, KPASSWD_REQ) 

2864 

2865 

2866KPASSWD_RESULTS = { 

2867 0: "KRB5_KPASSWD_SUCCESS", 

2868 1: "KRB5_KPASSWD_MALFORMED", 

2869 2: "KRB5_KPASSWD_HARDERROR", 

2870 3: "KRB5_KPASSWD_AUTHERROR", 

2871 4: "KRB5_KPASSWD_SOFTERROR", 

2872 5: "KRB5_KPASSWD_ACCESSDENIED", 

2873 6: "KRB5_KPASSWD_BAD_VERSION", 

2874 7: "KRB5_KPASSWD_INITIAL_FLAG_NEEDED", 

2875} 

2876 

2877 

2878class DOMAIN_PASSWORD_INFORMATION(Packet): 

2879 # [MS-SAMR] sect 2.2.3.5 

2880 fields_desc = [ 

2881 IntField("MinPasswordLength", 0), 

2882 IntField("PasswordHistoryLength", 0), 

2883 FlagsField( 

2884 "PasswordProperties", 

2885 0, 

2886 32, 

2887 { 

2888 0x00000001: "DOMAIN_PASSWORD_COMPLEX", 

2889 0x00000002: "DOMAIN_PASSWORD_NO_ANON_CHANGE", 

2890 0x00000004: "DOMAIN_PASSWORD_NO_CLEAR_CHANGE", 

2891 0x00000008: "DOMAIN_LOCKOUT_ADMINS", 

2892 0x00000010: "DOMAIN_PASSWORD_STORE_CLEARTEXT", 

2893 0x00000020: "DOMAIN_REFUSE_PASSWORD_CHANGE", 

2894 0x00000040: "DOMAIN_NO_LM_OWF_CHANGE", 

2895 }, 

2896 ), 

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

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

2899 ] 

2900 

2901 

2902class KPasswdResult(Packet): 

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

2904 fields_desc = [ 

2905 ShortField("PasswordInfoValid", 0), 

2906 PacketField( 

2907 "DomainPasswordInfo", 

2908 DOMAIN_PASSWORD_INFORMATION(), 

2909 DOMAIN_PASSWORD_INFORMATION, 

2910 ), 

2911 ] 

2912 

2913 

2914class _KPasswdRepDataResult_Field(StrField): 

2915 def m2i(self, pkt, s): 

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

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

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

2919 return KPasswdResult(val) 

2920 return val 

2921 

2922 

2923class KPasswdRepData(Packet): 

2924 fields_desc = [ 

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

2926 _KPasswdRepDataResult_Field("resultString", ""), 

2927 ] 

2928 

2929 

2930class Kpasswd(Packet): 

2931 @classmethod 

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

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

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

2935 return KPASSWD_REQ 

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

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

2938 if asn1_tag == 14: 

2939 return KPASSWD_REQ 

2940 elif asn1_tag == 15: 

2941 return KPASSWD_REP 

2942 return KPASSWD_REQ 

2943 

2944 

2945bind_bottom_up(UDP, Kpasswd, sport=464) 

2946bind_bottom_up(UDP, Kpasswd, dport=464) 

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

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

2949 

2950 

2951class KpasswdTCPHeader(Packet): 

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

2953 

2954 @classmethod 

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

2956 if len(data) < 4: 

2957 return None 

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

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

2960 return cls(data) 

2961 

2962 

2963bind_layers(KpasswdTCPHeader, Kpasswd) 

2964 

2965bind_bottom_up(TCP, KpasswdTCPHeader, sport=464) 

2966bind_layers(TCP, KpasswdTCPHeader, dport=464) 

2967 

2968# [MS-KKDCP] 

2969 

2970 

2971class KDC_PROXY_MESSAGE(ASN1_Packet): 

2972 ASN1_codec = ASN1_Codecs.BER 

2973 ASN1_root = ASN1F_SEQUENCE( 

2974 ASN1F_STRING_ENCAPS( 

2975 "kerbMessage", 

2976 KerberosTCPHeader(), 

2977 KerberosTCPHeader, 

2978 explicit_tag=0xA0, 

2979 ), 

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

2981 ASN1F_optional( 

2982 ASN1F_FLAGS( 

2983 "dclocatorHint", 

2984 None, 

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

2986 explicit_tag=0xA2, 

2987 ) 

2988 ), 

2989 ) 

2990 

2991 

2992class KdcProxySocket(SuperSocket): 

2993 """ 

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

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

2996 """ 

2997 

2998 def __init__( 

2999 self, 

3000 url, 

3001 targetDomain, 

3002 dclocatorHint=None, 

3003 no_check_certificate=False, 

3004 **kwargs, 

3005 ): 

3006 self.url = url 

3007 self.targetDomain = targetDomain 

3008 self.dclocatorHint = dclocatorHint 

3009 self.no_check_certificate = no_check_certificate 

3010 self.queue = deque() 

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

3012 

3013 def recv(self, x=None): 

3014 return self.queue.popleft() 

3015 

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

3017 from scapy.layers.http import HTTP_Client 

3018 

3019 cli = HTTP_Client(no_check_certificate=self.no_check_certificate) 

3020 try: 

3021 # sr it via the web client 

3022 resp = cli.request( 

3023 self.url, 

3024 Method="POST", 

3025 data=bytes( 

3026 # Wrap request in KDC_PROXY_MESSAGE 

3027 KDC_PROXY_MESSAGE( 

3028 kerbMessage=bytes(x), 

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

3030 # dclocatorHint is optional 

3031 dclocatorHint=self.dclocatorHint, 

3032 ) 

3033 ), 

3034 http_headers={ 

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

3036 "Pragma": "no-cache", 

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

3038 }, 

3039 ) 

3040 if resp and conf.raw_layer in resp: 

3041 # Parse the payload 

3042 resp = KDC_PROXY_MESSAGE(resp.load).kerbMessage 

3043 # We have an answer, queue it. 

3044 self.queue.append(resp) 

3045 else: 

3046 raise EOFError 

3047 finally: 

3048 cli.close() 

3049 

3050 @staticmethod 

3051 def select(sockets, remain=None): 

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

3053 

3054 

3055class IAKerbSocket(SuperSocket): 

3056 """ 

3057 Wrapper to forward messages back to our SPNEGO caller. 

3058 """ 

3059 

3060 def __init__( 

3061 self, 

3062 Context, 

3063 realm: str, 

3064 **kwargs, 

3065 ): 

3066 self.Context = Context 

3067 self.realm = realm.upper() 

3068 self.incoming = ObjectPipe("iak_incoming") 

3069 self.results = ObjectPipe("iak_results") 

3070 self.t = None 

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

3072 

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

3074 """ 

3075 recv when acting as a socket 

3076 """ 

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

3078 

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

3080 """ 

3081 send when acting as a socket 

3082 """ 

3083 x = x[KerberosTCPHeader].payload 

3084 

3085 # Wrap in the IAKERB header 

3086 pkt = KRB_GSSAPI_Token( 

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

3088 innerToken=KRB_InnerToken( 

3089 TOK_ID=b"\x05\x01", 

3090 root=IAKERB_HEADER( 

3091 targetRealm=ASN1_UTF8_STRING( 

3092 self.realm, 

3093 ) 

3094 ) 

3095 / x, 

3096 ), 

3097 ) 

3098 self.results.send( 

3099 ( 

3100 self.Context, 

3101 pkt, 

3102 GSS_S_CONTINUE_NEEDED, 

3103 ) 

3104 ) 

3105 

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

3107 """ 

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

3109 """ 

3110 try: 

3111 # Call initial function 

3112 result = func(**kwargs) 

3113 

3114 # Send result 

3115 self.results.send(result) 

3116 

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

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

3119 _, _, status = result 

3120 if status != GSS_S_CONTINUE_NEEDED: 

3121 self.Context.IAKerbSocket = None 

3122 self.shutdown() 

3123 

3124 except Exception as ex: 

3125 self.results.send(ex) 

3126 

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

3128 """ 

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

3130 """ 

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

3132 self.t.start() 

3133 

3134 def unpack(self, input_token): 

3135 """ 

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

3137 an IAKERB token. 

3138 """ 

3139 try: 

3140 # GSSAPI wrapping 

3141 input_token = input_token.root 

3142 except AttributeError: 

3143 pass 

3144 

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

3146 return input_token.innerToken.payload 

3147 

3148 return None 

3149 

3150 def next(self, input_token=None): 

3151 """ 

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

3153 """ 

3154 if input_token is not None: 

3155 # Make available in the incoming buffer of the socket 

3156 self.incoming.send(input_token) 

3157 

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

3159 try: 

3160 res = self.results.recv() 

3161 except IndexError: 

3162 raise EOFError 

3163 if isinstance(res, Exception): 

3164 # We also get the exceptions back from the thread 

3165 raise res 

3166 return res 

3167 

3168 def close(self): 

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

3170 pass 

3171 

3172 def shutdown(self): 

3173 self.incoming.close() 

3174 self.results.close() 

3175 

3176 def __del__(self): 

3177 self.shutdown() 

3178 

3179 @staticmethod 

3180 def select(sockets, remain=None): 

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

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

3183 

3184 

3185# Util functions 

3186 

3187 

3188class PKINIT_KEX_METHOD(IntEnum): 

3189 DIFFIE_HELLMAN = 1 

3190 PUBLIC_KEY = 2 

3191 

3192 

3193class KerberosClient(Automaton): 

3194 """ 

3195 Implementation of a Kerberos client. 

3196 

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

3198 wrap this client. 

3199 

3200 Common parameters: 

3201 

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

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

3204 :param upn: the UPN of the client. 

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

3206 :param password: the password of the client. 

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

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

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

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

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

3212 

3213 Advanced common parameters: 

3214 

3215 :param kdc_proxy: specify a KDC proxy url 

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

3217 :param fast: use FAST armoring 

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

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

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

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

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

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

3224 

3225 AS-REQ only: 

3226 

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

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

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

3230 only the ROOT CA is required. 

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

3232 'password' is the password of the p12. 

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

3234 Certificate based one for PKINIT. 

3235 

3236 TGS-REQ only: 

3237 

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

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

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

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

3242 :param u2u: sets the U2U flag 

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

3244 :param s4u2proxy: sets the S4U2Proxy flag 

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

3246 """ 

3247 

3248 RES_AS_MODE = namedtuple( 

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

3250 ) 

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

3252 

3253 class MODE(IntEnum): 

3254 AS_REQ = 0 

3255 TGS_REQ = 1 

3256 GET_SALT = 2 

3257 

3258 def __init__( 

3259 self, 

3260 mode=MODE.AS_REQ, 

3261 ip: Optional[str] = None, 

3262 upn: Optional[str] = None, 

3263 canonicalize: bool = False, 

3264 password: Optional[str] = None, 

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

3266 realm: Optional[str] = None, 

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

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

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

3270 no_verify_cert: bool = False, 

3271 p12: Optional[str] = None, 

3272 spn: Optional[str] = None, 

3273 ticket: Optional[KRB_Ticket] = None, 

3274 host: Optional[str] = None, 

3275 renew: bool = False, 

3276 additional_tickets: List[KRB_Ticket] = [], 

3277 u2u: bool = False, 

3278 for_user: Optional[str] = None, 

3279 s4u2proxy: bool = False, 

3280 dmsa: bool = False, 

3281 kdc_proxy: Optional[str] = None, 

3282 kdc_proxy_no_check_certificate: bool = False, 

3283 iakerb: bool = False, 

3284 iakerb_socket: Optional[IAKerbSocket] = None, 

3285 fast: bool = False, 

3286 armor_ticket: KRB_Ticket = None, 

3287 armor_ticket_upn: Optional[str] = None, 

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

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

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

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

3292 pkinit_kex_method: PKINIT_KEX_METHOD = PKINIT_KEX_METHOD.DIFFIE_HELLMAN, 

3293 port: int = 88, 

3294 timeout: int = 5, 

3295 verbose: bool = True, 

3296 **kwargs, 

3297 ): 

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

3299 from scapy.layers.ldap import dclocator 

3300 

3301 # PKINIT checks 

3302 if p12 is not None: 

3303 # password should be None or bytes 

3304 if isinstance(password, str): 

3305 password = password.encode() 

3306 

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

3308 # retry once. 

3309 while True: 

3310 try: 

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

3312 x509key, x509, _ = pkcs12.load_key_and_certificates( 

3313 fd.read(), 

3314 password=password, 

3315 ) 

3316 break 

3317 except ValueError as ex: 

3318 if password is None: 

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

3320 try: 

3321 from prompt_toolkit import prompt 

3322 

3323 password = prompt( 

3324 "Enter PKCS12 password: ", is_password=True 

3325 ) 

3326 except ImportError: 

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

3328 password = password.encode() 

3329 else: 

3330 raise ex 

3331 

3332 x509 = Cert(cryptography_obj=x509) 

3333 x509key = PrivKey(cryptography_obj=x509key) 

3334 elif x509 and x509key: 

3335 if not isinstance(x509, Cert): 

3336 x509 = Cert(x509) 

3337 if not isinstance(x509key, PrivKey): 

3338 x509key = PrivKey(x509key) 

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

3340 ca = CertList(ca) 

3341 if upn is None and x509: 

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

3343 if realm is None: 

3344 raise ValueError( 

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

3346 ) 

3347 for ext in x509.extensions: 

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

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

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

3351 break 

3352 if upn is None: 

3353 raise ValueError( 

3354 "Could not find subjectAltName in certificate !" 

3355 " Please provide a UPN." 

3356 ) 

3357 canonicalize = True 

3358 

3359 # UPN, SPN and realm calculation 

3360 if not upn: 

3361 raise ValueError("Invalid upn") 

3362 if realm is None: 

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

3364 _, realm = _parse_upn(upn) 

3365 elif mode == self.MODE.TGS_REQ: 

3366 _, realm = _parse_spn(spn) 

3367 if not realm and ticket: 

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

3369 # of the ticket. 

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

3371 else: 

3372 raise ValueError("Invalid realm") 

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

3374 spn = "krbtgt/" + realm 

3375 elif not spn: 

3376 raise ValueError("Invalid spn") 

3377 

3378 # Extra checks for specific requests 

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

3380 if not host: 

3381 raise ValueError("Invalid host") 

3382 if x509 is not None: 

3383 if x509key and not ca: 

3384 if not no_verify_cert: 

3385 raise ValueError( 

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

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

3388 ) 

3389 else: 

3390 ca = [] 

3391 elif not x509key or not ca: 

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

3393 elif mode == self.MODE.TGS_REQ: 

3394 if not ticket: 

3395 raise ValueError("Invalid ticket") 

3396 

3397 if not ip and not kdc_proxy and not iakerb: 

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

3399 ip = dclocator( 

3400 realm, 

3401 timeout=1, 

3402 # Use connect mode instead of ldap for compatibility 

3403 # with MIT kerberos servers 

3404 mode="connect", 

3405 port=port, 

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

3407 ).ip 

3408 

3409 # Armoring checks 

3410 if fast: 

3411 if mode == self.MODE.AS_REQ: 

3412 # Requires an external ticket 

3413 if not armor_ticket or not armor_ticket_upn or not armor_ticket_skey: 

3414 raise ValueError( 

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

3416 "please provide the 3 required armor arguments" 

3417 ) 

3418 elif mode == self.MODE.TGS_REQ: 

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

3420 raise ValueError( 

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

3422 ) 

3423 

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

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

3426 if mode == self.MODE.GET_SALT: 

3427 if etypes is not None: 

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

3429 

3430 etypes = [ 

3431 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3432 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3433 ] 

3434 elif etypes is None: 

3435 etypes = [ 

3436 EncryptionType.AES256_CTS_HMAC_SHA1_96, 

3437 EncryptionType.AES128_CTS_HMAC_SHA1_96, 

3438 EncryptionType.RC4_HMAC, 

3439 EncryptionType.DES_CBC_MD5, 

3440 ] 

3441 self.etypes = etypes 

3442 

3443 self.mode = mode 

3444 

3445 self.result = None # Result 

3446 

3447 self._timeout = timeout 

3448 self._verbose = verbose 

3449 self._ip = ip 

3450 self._port = port 

3451 self.kdc_proxy = kdc_proxy 

3452 self.kdc_proxy_no_check_certificate = kdc_proxy_no_check_certificate 

3453 self.iakerb = iakerb 

3454 self.iakerb_socket = iakerb_socket 

3455 

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

3457 self.host = host.upper() 

3458 self.password = password and bytes_encode(password) 

3459 self.spn = spn 

3460 self.upn = upn 

3461 self.canonicalize = canonicalize # Whether we request canonicalization 

3462 self.realm = realm.upper() 

3463 self.x509 = x509 

3464 self.x509key = x509key 

3465 self.pkinit_kex_method = pkinit_kex_method 

3466 self.ticket = ticket 

3467 self.fast = fast 

3468 self.armor_ticket = armor_ticket 

3469 self.armor_ticket_upn = armor_ticket_upn 

3470 self.armor_ticket_skey = armor_ticket_skey 

3471 self.key_list_req = key_list_req 

3472 self.renew = renew 

3473 self.additional_tickets = additional_tickets # U2U + S4U2Proxy 

3474 self.u2u = u2u # U2U 

3475 self.for_user = for_user # FOR-USER 

3476 self.s4u2proxy = s4u2proxy # S4U2Proxy 

3477 self.dmsa = dmsa # DMSA 

3478 self.key = key 

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

3480 self.replykey = None # Key used for reply 

3481 # See RFC4120 - sect 7.2.2 

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

3483 self.should_followup = False 

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

3485 self.fast_req_sent = False 

3486 # Session parameters 

3487 if self.x509: 

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

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

3490 self.pre_auth = True 

3491 else: 

3492 self.pre_auth = False 

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

3494 self.fast_rep = None 

3495 self.fast_error = None 

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

3497 self.fast_armorkey = None # The armor key 

3498 self.fxcookie = None 

3499 self.pkinit_dh_key = None 

3500 self.no_verify_cert = no_verify_cert 

3501 if ca is not None: 

3502 self.pkinit_cms = CMS_Engine(ca) 

3503 else: 

3504 self.pkinit_cms = None 

3505 if dhashes is None: 

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

3507 else: 

3508 self.dhashes = dhashes 

3509 

3510 # Launch the client 

3511 sock = self._connect() 

3512 super(KerberosClient, self).__init__( 

3513 sock=sock, 

3514 **kwargs, 

3515 ) 

3516 

3517 def _connect(self): 

3518 """ 

3519 Internal function to bind a socket to the DC. 

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

3521 """ 

3522 if self.kdc_proxy: 

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

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

3525 sock = KdcProxySocket( 

3526 url=self.kdc_proxy, 

3527 targetDomain=self.realm, 

3528 no_check_certificate=self.kdc_proxy_no_check_certificate, 

3529 ) 

3530 elif self.iakerb: 

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

3532 # takes our messages and transport them over GSSAPI. 

3533 sock = self.iakerb_socket 

3534 else: 

3535 sock = socket.socket() 

3536 sock.settimeout(self._timeout) 

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

3538 sock = StreamSocket(sock, KerberosTCPHeader) 

3539 return sock 

3540 

3541 def send(self, pkt): 

3542 """ 

3543 Sends a wrapped Kerberos packet 

3544 """ 

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

3546 

3547 def _show_krb_error(self, error): 

3548 """ 

3549 Displays a Kerberos error 

3550 """ 

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

3552 # KDC_ERR_S_PRINCIPAL_UNKNOWN 

3553 if ( 

3554 isinstance(error.root.eData, KERB_ERROR_UNK) 

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

3556 ): 

3557 log_runtime.error( 

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

3559 ) 

3560 else: 

3561 log_runtime.error( 

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

3563 % error.root.getSPN() 

3564 ) 

3565 else: 

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

3567 if self._verbose: 

3568 error.show() 

3569 

3570 def _base_kdc_req(self, now_time): 

3571 """ 

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

3573 """ 

3574 kdcreq = KRB_KDC_REQ_BODY( 

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

3576 additionalTickets=None, 

3577 # Windows default 

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

3579 cname=None, 

3580 realm=ASN1_GENERAL_STRING(self.realm), 

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

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

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

3584 ) 

3585 if self.renew: 

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

3587 return kdcreq 

3588 

3589 def calc_fast_armorkey(self): 

3590 """ 

3591 Calculate and return the FAST armorkey 

3592 """ 

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

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

3595 # AS-REQ mode 

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

3597 

3598 self.fast_armorkey = KRB_FX_CF2( 

3599 self.fast_skey, 

3600 self.armor_ticket_skey, 

3601 b"subkeyarmor", 

3602 b"ticketarmor", 

3603 ) 

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

3605 # TGS-REQ: 2 cases 

3606 

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

3608 

3609 if not self.armor_ticket: 

3610 # Case 1: Implicit armoring 

3611 self.fast_armorkey = KRB_FX_CF2( 

3612 self.subkey, 

3613 self.key, 

3614 b"subkeyarmor", 

3615 b"ticketarmor", 

3616 ) 

3617 else: 

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

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

3620 

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

3622 

3623 explicit_armor_key = KRB_FX_CF2( 

3624 self.fast_skey, 

3625 self.armor_ticket_skey, 

3626 b"subkeyarmor", 

3627 b"ticketarmor", 

3628 ) 

3629 

3630 self.fast_armorkey = KRB_FX_CF2( 

3631 explicit_armor_key, 

3632 self.subkey, 

3633 b"explicitarmor", 

3634 b"tgsarmor", 

3635 ) 

3636 

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

3638 """ 

3639 :param kdc_req: the KDC_REQ_BODY to wrap 

3640 :param padata: the list of PADATA to wrap 

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

3642 """ 

3643 

3644 # Create the PA Fast request wrapper 

3645 pafastreq = PA_FX_FAST_REQUEST( 

3646 armoredData=KrbFastArmoredReq( 

3647 reqChecksum=Checksum(), 

3648 encFastReq=EncryptedData(), 

3649 ) 

3650 ) 

3651 

3652 if self.armor_ticket is not None: 

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

3654 

3655 pafastreq.armoredData.armor = KrbFastArmor( 

3656 armorType=1, # FX_FAST_ARMOR_AP_REQUEST 

3657 armorValue=KRB_AP_REQ( 

3658 ticket=self.armor_ticket, 

3659 authenticator=EncryptedData(), 

3660 ), 

3661 ) 

3662 

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

3664 _, crealm = _parse_upn(self.armor_ticket_upn) 

3665 authenticator = KRB_Authenticator( 

3666 crealm=ASN1_GENERAL_STRING(crealm), 

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

3668 cksum=None, 

3669 ctime=ASN1_GENERALIZED_TIME(now_time), 

3670 cusec=ASN1_INTEGER(0), 

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

3672 seqNumber=ASN1_INTEGER(0), 

3673 encAuthorizationData=None, 

3674 ) 

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

3676 self.armor_ticket_skey, 

3677 authenticator, 

3678 ) 

3679 

3680 # Sign the fast request wrapper 

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

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

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

3684 pafastreq.armoredData.reqChecksum.make( 

3685 self.fast_armorkey, 

3686 bytes(pa_tgsreq_ap), 

3687 ) 

3688 else: 

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

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

3691 # containing message" 

3692 pafastreq.armoredData.reqChecksum.make( 

3693 self.fast_armorkey, 

3694 bytes(kdc_req), 

3695 ) 

3696 

3697 # Build and encrypt the Fast request 

3698 fastreq = KrbFastReq( 

3699 padata=padata, 

3700 reqBody=kdc_req, 

3701 ) 

3702 pafastreq.armoredData.encFastReq.encrypt( 

3703 self.fast_armorkey, 

3704 fastreq, 

3705 ) 

3706 

3707 # Return the PADATA 

3708 return PADATA( 

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

3710 padataValue=pafastreq, 

3711 ) 

3712 

3713 def as_req(self): 

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

3715 

3716 # 1. Build and populate KDC-REQ 

3717 kdc_req = self._base_kdc_req(now_time=now_time) 

3718 kdc_req.addresses = [ 

3719 HostAddress( 

3720 addrType=ASN1_INTEGER(20), # Netbios 

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

3722 ) 

3723 ] 

3724 kdc_req.addresses = None 

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

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

3727 

3728 # 2. Build the list of PADATA 

3729 padata = [ 

3730 PADATA( 

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

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

3733 ) 

3734 ] 

3735 

3736 # Cookie support 

3737 if self.fxcookie: 

3738 padata.insert( 

3739 0, 

3740 PADATA( 

3741 padataType=133, # PA-FX-COOKIE 

3742 padataValue=self.fxcookie, 

3743 ), 

3744 ) 

3745 

3746 # FAST 

3747 if self.fast: 

3748 # Calculate the armor key 

3749 self.calc_fast_armorkey() 

3750 

3751 # [MS-KILE] sect 3.2.5.5 

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

3753 padata.append( 

3754 PADATA( 

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

3756 padataValue=PA_PAC_OPTIONS( 

3757 options="Claims", 

3758 ), 

3759 ) 

3760 ) 

3761 

3762 # Pre-auth is requested 

3763 if self.pre_auth: 

3764 if self.x509: 

3765 # Special PKINIT (RFC4556) factor 

3766 

3767 # RFC4556 - 3.2.1. Generation of Client Request 

3768 

3769 # RFC4556 - 3.2.1 - (5) AuthPack 

3770 authpack = KRB_AuthPack( 

3771 pkAuthenticator=KRB_PKAuthenticator( 

3772 ctime=ASN1_GENERALIZED_TIME(now_time), 

3773 cusec=ASN1_INTEGER(0), 

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

3775 ), 

3776 clientPublicValue=None, # Used only in DH mode 

3777 supportedCMSTypes=[], 

3778 clientDHNonce=None, 

3779 supportedKDFs=None, 

3780 ) 

3781 

3782 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

3783 # RFC4556 - 3.2.3.1. Diffie-Hellman Key Exchange 

3784 

3785 # We (and Windows) use modp2048 

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

3787 self.pkinit_dh_key = dh_parameters.generate_private_key() 

3788 numbers = dh_parameters.parameter_numbers() 

3789 

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

3791 # and we want the DomainParameters format. 

3792 authpack.clientPublicValue = X509_SubjectPublicKeyInfo( 

3793 signatureAlgorithm=X509_AlgorithmIdentifier( 

3794 algorithm=ASN1_OID("dhpublicnumber"), 

3795 parameters=DomainParameters( 

3796 p=ASN1_INTEGER(numbers.p), 

3797 g=ASN1_INTEGER(numbers.g), 

3798 # q: see ERRATA 1 of RFC4556 

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

3800 j=None, 

3801 ), 

3802 ), 

3803 subjectPublicKey=DHPublicKey( 

3804 y=ASN1_INTEGER( 

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

3806 ), 

3807 ), 

3808 ) 

3809 elif self.pkinit_kex_method == PKINIT_KEX_METHOD.PUBLIC_KEY: 

3810 # RFC4556 - 3.2.3.2. - Public Key Encryption 

3811 

3812 # Set supportedCMSTypes, supportedKDFs 

3813 authpack.supportedCMSTypes = [ 

3814 X509_AlgorithmIdentifier(algorithm=ASN1_OID(x)) 

3815 for x in [ 

3816 "ecdsa-with-SHA512", 

3817 "ecdsa-with-SHA256", 

3818 "sha512WithRSAEncryption", 

3819 "sha256WithRSAEncryption", 

3820 ] 

3821 ] 

3822 authpack.supportedKDFs = [ 

3823 KDFAlgorithmId(kdfId=ASN1_OID(x)) 

3824 for x in [ 

3825 "id-pkinit-kdf-sha256", 

3826 "id-pkinit-kdf-sha1", 

3827 "id-pkinit-kdf-sha512", 

3828 ] 

3829 ] 

3830 

3831 # XXX UNFINISHED 

3832 raise NotImplementedError 

3833 else: 

3834 raise ValueError 

3835 

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

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

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

3839 

3840 # Populate paChecksum 

3841 authpack.pkAuthenticator.make_checksum( 

3842 bytes(kdc_req), 

3843 h=dhash, 

3844 ) 

3845 

3846 # Sign the AuthPack 

3847 signedAuthpack = self.pkinit_cms.sign( 

3848 authpack, 

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

3850 self.x509, 

3851 self.x509key, 

3852 dhash=dhash, 

3853 ) 

3854 

3855 # Build PA-DATA 

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

3857 pafactor = PADATA( 

3858 padataType=self.pa_type, 

3859 padataValue=PA_PK_AS_REQ( 

3860 signedAuthpack=signedAuthpack, 

3861 trustedCertifiers=None, 

3862 kdcPkId=None, 

3863 ), 

3864 ) 

3865 

3866 # RFC 4557 extension - OCSP 

3867 padata.insert( 

3868 0, 

3869 PADATA( 

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

3871 ), 

3872 ) 

3873 else: 

3874 # Key-based factor 

3875 

3876 if self.fast: 

3877 # Special FAST factor 

3878 # RFC6113 sect 5.4.6 

3879 

3880 # Calculate the 'challenge key' 

3881 ts_key = KRB_FX_CF2( 

3882 self.fast_armorkey, 

3883 self.key, 

3884 b"clientchallengearmor", 

3885 b"challengelongterm", 

3886 ) 

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

3888 pafactor = PADATA( 

3889 padataType=self.pa_type, 

3890 padataValue=EncryptedData(), 

3891 ) 

3892 else: 

3893 # Usual 'timestamp' factor 

3894 ts_key = self.key 

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

3896 pafactor = PADATA( 

3897 padataType=self.pa_type, 

3898 padataValue=EncryptedData(), 

3899 ) 

3900 pafactor.padataValue.encrypt( 

3901 ts_key, 

3902 PA_ENC_TS_ENC(patimestamp=ASN1_GENERALIZED_TIME(now_time)), 

3903 ) 

3904 

3905 # Insert Pre-Authentication data 

3906 padata.insert( 

3907 0, 

3908 pafactor, 

3909 ) 

3910 

3911 # FAST support 

3912 if self.fast: 

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

3914 # hidden inside the encrypted section. 

3915 padata = [ 

3916 self._fast_wrap( 

3917 kdc_req=kdc_req, 

3918 padata=padata, 

3919 now_time=now_time, 

3920 ) 

3921 ] 

3922 

3923 # 3. Build the request 

3924 asreq = Kerberos( 

3925 root=KRB_AS_REQ( 

3926 padata=padata, 

3927 reqBody=kdc_req, 

3928 ) 

3929 ) 

3930 

3931 # Note the reply key 

3932 self.replykey = self.key 

3933 

3934 return asreq 

3935 

3936 def tgs_req(self): 

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

3938 

3939 # Compute armor key for FAST 

3940 if self.fast: 

3941 self.calc_fast_armorkey() 

3942 

3943 # 1. Build and populate KDC-REQ 

3944 kdc_req = self._base_kdc_req(now_time=now_time) 

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

3946 

3947 # Additional tickets 

3948 if self.additional_tickets: 

3949 kdc_req.additionalTickets = self.additional_tickets 

3950 

3951 # U2U 

3952 if self.u2u: 

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

3954 

3955 # 2. Build the list of PADATA 

3956 padata = [] 

3957 

3958 # [MS-SFU] FOR-USER extension 

3959 if self.for_user is not None: 

3960 # [MS-SFU] note 4: 

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

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

3963 # certificate is available. 

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

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

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

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

3968 

3969 # 1. Add PA_S4U_X509_USER 

3970 pasfux509 = PA_S4U_X509_USER( 

3971 userId=S4UUserID( 

3972 nonce=kdc_req.nonce, 

3973 # [MS-SFU] note 5: 

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

3975 options="USE_REPLY_KEY_USAGE", 

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

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

3978 subjectCertificate=None, # TODO 

3979 ), 

3980 checksum=Checksum(), 

3981 ) 

3982 

3983 if self.dmsa: 

3984 # DMSA = set UNCONDITIONAL_DELEGATION to 1 

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

3986 

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

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

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

3990 pasfux509.checksum.make( 

3991 self.key, 

3992 bytes(pasfux509.userId), 

3993 cksumtype=ChecksumType.RSA_MD4, 

3994 ) 

3995 else: 

3996 pasfux509.checksum.make( 

3997 self.key, 

3998 bytes(pasfux509.userId), 

3999 ) 

4000 padata.append( 

4001 PADATA( 

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

4003 padataValue=pasfux509, 

4004 ) 

4005 ) 

4006 

4007 # 2. Add PA_FOR_USER 

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

4009 paforuser = PA_FOR_USER( 

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

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

4012 cksum=Checksum(), 

4013 ) 

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

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

4016 ) + ( 

4017 ( 

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

4019 + paforuser.userRealm.val 

4020 + paforuser.authPackage.val 

4021 ).encode() 

4022 ) 

4023 paforuser.cksum.make( 

4024 self.key, 

4025 S4UByteArray, 

4026 cksumtype=ChecksumType.HMAC_MD5, 

4027 ) 

4028 padata.append( 

4029 PADATA( 

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

4031 padataValue=paforuser, 

4032 ) 

4033 ) 

4034 

4035 # [MS-SFU] S4U2proxy - sect 3.1.5.2.1 

4036 if self.s4u2proxy: 

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

4038 padata.append( 

4039 PADATA( 

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

4041 padataValue=PA_PAC_OPTIONS( 

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

4043 ), 

4044 ) 

4045 ) 

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

4047 kdc_req.kdcOptions.set(14, 1) 

4048 

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

4050 if self.key_list_req: 

4051 padata.append( 

4052 PADATA( 

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

4054 padataValue=KERB_KEY_LIST_REQ( 

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

4056 ), 

4057 ) 

4058 ) 

4059 

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

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

4062 pa_tgs_req = PADATA( 

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

4064 padataValue=apreq, 

4065 ) 

4066 

4067 # 4. Populate it's authenticator 

4068 _, crealm = _parse_upn(self.upn) 

4069 authenticator = KRB_Authenticator( 

4070 crealm=ASN1_GENERAL_STRING(crealm), 

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

4072 cksum=None, 

4073 ctime=ASN1_GENERALIZED_TIME(now_time), 

4074 cusec=ASN1_INTEGER(0), 

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

4076 seqNumber=None, 

4077 encAuthorizationData=None, 

4078 ) 

4079 

4080 # Compute checksum 

4081 if self.key.cksumtype: 

4082 authenticator.cksum = Checksum() 

4083 authenticator.cksum.make( 

4084 self.key, 

4085 bytes(kdc_req), 

4086 ) 

4087 

4088 # Encrypt authenticator 

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

4090 

4091 # 5. Process FAST if required 

4092 if self.fast: 

4093 padata = [ 

4094 self._fast_wrap( 

4095 kdc_req=kdc_req, 

4096 padata=padata, 

4097 now_time=now_time, 

4098 pa_tgsreq_ap=apreq, 

4099 ) 

4100 ] 

4101 

4102 # 6. Add the final PADATA 

4103 padata.append(pa_tgs_req) 

4104 

4105 # 7. Build the request 

4106 tgsreq = Kerberos( 

4107 root=KRB_TGS_REQ( 

4108 padata=padata, 

4109 reqBody=kdc_req, 

4110 ) 

4111 ) 

4112 

4113 # Note the reply key 

4114 if self.subkey: 

4115 self.replykey = self.subkey 

4116 else: 

4117 self.replykey = self.key 

4118 

4119 return tgsreq 

4120 

4121 @ATMT.state(initial=1) 

4122 def BEGIN(self): 

4123 pass 

4124 

4125 @ATMT.condition(BEGIN) 

4126 def should_send_as_req(self): 

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

4128 raise self.SENT_AS_REQ() 

4129 

4130 @ATMT.condition(BEGIN) 

4131 def should_send_tgs_req(self): 

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

4133 raise self.SENT_TGS_REQ() 

4134 

4135 @ATMT.action(should_send_as_req) 

4136 def send_as_req(self): 

4137 self.send(self.as_req()) 

4138 

4139 @ATMT.action(should_send_tgs_req) 

4140 def send_tgs_req(self): 

4141 self.send(self.tgs_req()) 

4142 

4143 @ATMT.state() 

4144 def SENT_AS_REQ(self): 

4145 pass 

4146 

4147 @ATMT.state() 

4148 def SENT_TGS_REQ(self): 

4149 pass 

4150 

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

4152 """ 

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

4154 

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

4156 """ 

4157 salt = b"" 

4158 

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

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

4161 

4162 # 1. Process pa-data 

4163 if padatas is not None: 

4164 for padata in padatas: 

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

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

4167 elt = padata.padataValue.seq[0] 

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

4169 etype = elt.etype.val 

4170 if etype != EncryptionType.RC4_HMAC: 

4171 salt = elt.salt.val 

4172 

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

4174 # PKINIT handling 

4175 

4176 # The steps are as follows: 

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

4178 # is different depending on the used method. 

4179 # 2. Compute the replykey 

4180 

4181 if self.pkinit_kex_method == PKINIT_KEX_METHOD.DIFFIE_HELLMAN: 

4182 # Unpack KDCDHKeyInfo 

4183 keyinfo = self.pkinit_cms.verify( 

4184 padata.padataValue.rep.dhSignedData, 

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

4186 no_verify_cert=self.no_verify_cert, 

4187 ) 

4188 

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

4190 # the CMS successfully, end here. 

4191 if etype is None: 

4192 continue 

4193 

4194 # Extract crypto parameters 

4195 y = keyinfo.subjectPublicKey.y.val 

4196 

4197 # Import into cryptography 

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

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

4200 

4201 # Calculate DHSharedSecret 

4202 DHSharedSecret = self.pkinit_dh_key.exchange(pubkey) 

4203 

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

4205 self.replykey = octetstring2key( 

4206 etype, 

4207 DHSharedSecret, 

4208 ) 

4209 

4210 else: 

4211 raise ValueError 

4212 

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

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

4215 

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

4217 # Get cookie and store it 

4218 self.fxcookie = padata.padataValue 

4219 

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

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

4222 if isinstance(padata.padataValue, PA_FX_FAST_REPLY): 

4223 self.fast_rep = ( 

4224 padata.padataValue.armoredData.encFastRep.decrypt( 

4225 self.fast_armorkey, 

4226 ) 

4227 ) 

4228 

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

4230 # Get error and store it 

4231 self.fast_error = padata.padataValue 

4232 

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

4234 # Verify S4U checksum 

4235 key_usage_number = None 

4236 pasfux509 = padata.padataValue 

4237 # [MS-SFU] sect 2.2.2 

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

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

4240 key_usage_number = 27 

4241 pasfux509.checksum.verify( 

4242 self.key, 

4243 bytes(pasfux509.userId), 

4244 key_usage_number=key_usage_number, 

4245 ) 

4246 

4247 # 2. Update the current keys if necessary 

4248 

4249 # Compute client key if not already provided 

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

4251 self.key = Key.string_to_key( 

4252 etype, 

4253 self.password, 

4254 salt, 

4255 ) 

4256 

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

4258 if self.fast_rep and self.fast_rep.strengthenKey: 

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

4260 self.replykey = KRB_FX_CF2( 

4261 self.fast_rep.strengthenKey.toKey(), 

4262 self.replykey, 

4263 b"strengthenkey", 

4264 b"replykey", 

4265 ) 

4266 

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

4268 def receive_salt_mode(self, pkt): 

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

4270 # exit. 

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

4272 if Kerberos not in pkt: 

4273 raise self.FINAL() 

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

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

4276 raise self.FINAL() 

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

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

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

4280 elt = padata.padataValue.seq[0] 

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

4282 self.result = elt.salt.val 

4283 raise self.FINAL() 

4284 else: 

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

4286 raise self.FINAL() 

4287 

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

4289 def receive_krb_error_as_req(self, pkt): 

4290 # We check for Kerberos errors. 

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

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

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

4294 # Process PAs if available 

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

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

4297 

4298 # Special case for FAST errors 

4299 if self.fast_rep: 

4300 # This is actually a fast response error ! 

4301 frep, self.fast_rep = self.fast_rep, None 

4302 # Re-process PAs 

4303 self._process_padatas_and_key(frep.padata) 

4304 # Extract real Kerberos error from FAST message 

4305 ferr = Kerberos(root=self.fast_error) 

4306 self.fast_error = None 

4307 # Recurse 

4308 self.receive_krb_error_as_req(ferr) 

4309 return 

4310 

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

4312 if not self.key: 

4313 log_runtime.error( 

4314 "Got 'KDC_ERR_PREAUTH_REQUIRED', " 

4315 "but no possible key could be computed." 

4316 ) 

4317 raise self.FINAL() 

4318 self.should_followup = True 

4319 self.pre_auth = True 

4320 raise self.BEGIN() 

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

4322 self.should_followup = True 

4323 raise self.BEGIN() 

4324 else: 

4325 self._show_krb_error(pkt) 

4326 raise self.FINAL() 

4327 

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

4329 def receive_as_rep(self, pkt): 

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

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

4332 

4333 @ATMT.eof(SENT_AS_REQ) 

4334 def retry_after_eof_in_apreq(self): 

4335 if self.should_followup: 

4336 # Reconnect and Restart 

4337 self.should_followup = False 

4338 self.update_sock(self._connect()) 

4339 raise self.BEGIN() 

4340 else: 

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

4342 raise self.FINAL() 

4343 

4344 @ATMT.action(receive_as_rep) 

4345 def decrypt_as_rep(self, pkt): 

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

4347 self._process_padatas_and_key( 

4348 pkt.root.padata, 

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

4350 ) 

4351 

4352 if not self.pre_auth: 

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

4354 

4355 # Process FAST response 

4356 if self.fast_rep: 

4357 # Verify the ticket-checksum 

4358 self.fast_rep.finished.ticketChecksum.verify( 

4359 self.fast_armorkey, 

4360 bytes(pkt.root.ticket), 

4361 ) 

4362 # Process pa of FAST response 

4363 self._process_padatas_and_key( 

4364 self.fast_rep.padata, 

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

4366 ) 

4367 self.fast_rep = None 

4368 elif self.fast: 

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

4370 

4371 # Check for PKINIT 

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

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

4374 

4375 # Decrypt AS-REP response 

4376 enc = pkt.root.encPart 

4377 res = enc.decrypt(self.replykey) 

4378 self.result = self.RES_AS_MODE( 

4379 pkt.root, 

4380 res.key.toKey(), 

4381 res, 

4382 pkt.root.getUPN(), 

4383 self.pa_type, 

4384 ) 

4385 

4386 @ATMT.receive_condition(SENT_TGS_REQ) 

4387 def receive_krb_error_tgs_req(self, pkt): 

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

4389 # Process PAs if available 

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

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

4392 

4393 if self.fast_rep: 

4394 # This is actually a fast response error ! 

4395 frep, self.fast_rep = self.fast_rep, None 

4396 # Re-process PAs 

4397 self._process_padatas_and_key(frep.padata) 

4398 # Extract real Kerberos error from FAST message 

4399 ferr = Kerberos(root=self.fast_error) 

4400 self.fast_error = None 

4401 # Recurse 

4402 self.receive_krb_error_tgs_req(ferr) 

4403 return 

4404 

4405 self._show_krb_error(pkt) 

4406 raise self.FINAL() 

4407 

4408 @ATMT.receive_condition(SENT_TGS_REQ) 

4409 def receive_tgs_rep(self, pkt): 

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

4411 if ( 

4412 not self.renew 

4413 and not self.dmsa 

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

4415 ): 

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

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

4418 

4419 @ATMT.action(receive_tgs_rep) 

4420 def decrypt_tgs_rep(self, pkt): 

4421 self._process_padatas_and_key(pkt.root.padata) 

4422 

4423 # Process FAST response 

4424 if self.fast_rep: 

4425 # Verify the ticket-checksum 

4426 self.fast_rep.finished.ticketChecksum.verify( 

4427 self.fast_armorkey, 

4428 bytes(pkt.root.ticket), 

4429 ) 

4430 self.fast_rep = None 

4431 elif self.fast: 

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

4433 

4434 # Decrypt TGS-REP response 

4435 enc = pkt.root.encPart 

4436 if self.subkey: 

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

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

4439 # authenticator subkey is used." 

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

4441 else: 

4442 res = enc.decrypt(self.replykey) 

4443 

4444 # Store result 

4445 self.result = self.RES_TGS_MODE( 

4446 pkt.root, 

4447 res.key.toKey(), 

4448 res, 

4449 self.upn, 

4450 ) 

4451 

4452 @ATMT.state(final=1) 

4453 def FINAL(self): 

4454 pass 

4455 

4456 

4457def _parse_upn(upn): 

4458 """ 

4459 Extract the username and realm from full UPN 

4460 """ 

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

4462 if not m: 

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

4464 if "/" in upn: 

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

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

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

4468 raise ValueError(err) 

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

4470 user = m.group(1) 

4471 domain = m.group(3) 

4472 else: 

4473 user = m.group(3) 

4474 domain = m.group(1) 

4475 return user, domain 

4476 

4477 

4478def _parse_spn(spn): 

4479 """ 

4480 Extract ServiceName and realm from full SPN 

4481 """ 

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

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

4484 if not m: 

4485 try: 

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

4487 return _parse_upn(spn) 

4488 except ValueError: 

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

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

4491 

4492 

4493def _spn_are_equal(spn1, spn2): 

4494 """ 

4495 Check that two SPNs are equal. 

4496 """ 

4497 spn1, _ = _parse_spn(spn1) 

4498 spn2, _ = _parse_spn(spn2) 

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

4500 

4501 

4502def krb_as_req( 

4503 upn: Optional[str] = None, 

4504 spn: Optional[str] = None, 

4505 ip: Optional[str] = None, 

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

4507 password: Optional[str] = None, 

4508 realm: Optional[str] = None, 

4509 host: str = "WIN10", 

4510 p12: Optional[str] = None, 

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

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

4513 **kwargs, 

4514): 

4515 r""" 

4516 Kerberos AS-Req 

4517 

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

4519 or "user@DOMAIN" 

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

4521 Defaults to "krbtgt/<realm>" 

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

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

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

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

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

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

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

4529 'password' is the password of the p12. 

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

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

4532 

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

4534 

4535 Example:: 

4536 

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

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

4539 

4540 Equivalent:: 

4541 

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

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

4544 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

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

4546 

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

4548 

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

4550 """ 

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

4552 if password is None: 

4553 try: 

4554 from prompt_toolkit import prompt 

4555 

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

4557 except ImportError: 

4558 password = input("Enter password: ") 

4559 cli = KerberosClient( 

4560 mode=KerberosClient.MODE.AS_REQ, 

4561 realm=realm, 

4562 ip=ip, 

4563 spn=spn, 

4564 host=host, 

4565 upn=upn, 

4566 password=password, 

4567 key=key, 

4568 p12=p12, 

4569 x509=x509, 

4570 x509key=x509key, 

4571 **kwargs, 

4572 ) 

4573 cli.run() 

4574 cli.stop() 

4575 return cli.result 

4576 

4577 

4578def krb_tgs_req( 

4579 upn, 

4580 spn, 

4581 sessionkey, 

4582 ticket, 

4583 ip=None, 

4584 renew=False, 

4585 realm=None, 

4586 additional_tickets=[], 

4587 u2u=False, 

4588 etypes=None, 

4589 for_user=None, 

4590 s4u2proxy=False, 

4591 **kwargs, 

4592): 

4593 r""" 

4594 Kerberos TGS-Req 

4595 

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

4597 or "user@DOMAIN" 

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

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

4600 :param ticket: the tgt ticket 

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

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

4603 :param renew: ask for renewal 

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

4605 :param additional_tickets: (optional) a list of additional tickets to pass. 

4606 :param u2u: (optional) if specified, enable U2U and request the ticket to be 

4607 signed using the session key from the first additional ticket. 

4608 :param etypes: array of EncryptionType values. 

4609 By default: AES128, AES256, RC4, DES_MD5 

4610 :param for_user: a user principal name to request the ticket for. This is the 

4611 S4U2Self extension. 

4612 

4613 :return: returns a named tuple (tgsrep=<...>, sessionkey=<...>) 

4614 

4615 Example:: 

4616 

4617 >>> # The KDC is on 192.168.122.17, we ask a TGT for user1 

4618 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", password="Password1") 

4619 

4620 Equivalent:: 

4621 

4622 >>> from scapy.libs.rfc3961 import Key, EncryptionType 

4623 >>> key = Key(EncryptionType.AES256_CTS_HMAC_SHA1_96, key=hex_bytes("6d0748c546 

4624 ...: f4e99205e78f8da7681d4ec5520ae4815543720c2a647c1ae814c9")) 

4625 >>> krb_as_req("user1@DOMAIN.LOCAL", "192.168.122.17", key=key) 

4626 """ 

4627 cli = KerberosClient( 

4628 mode=KerberosClient.MODE.TGS_REQ, 

4629 realm=realm, 

4630 upn=upn, 

4631 ip=ip, 

4632 spn=spn, 

4633 key=sessionkey, 

4634 ticket=ticket, 

4635 renew=renew, 

4636 additional_tickets=additional_tickets, 

4637 u2u=u2u, 

4638 etypes=etypes, 

4639 for_user=for_user, 

4640 s4u2proxy=s4u2proxy, 

4641 **kwargs, 

4642 ) 

4643 cli.run() 

4644 cli.stop() 

4645 return cli.result 

4646 

4647 

4648def krb_as_and_tgs(upn, spn, ip=None, key=None, password=None, **kwargs): 

4649 """ 

4650 Kerberos AS-Req then TGS-Req 

4651 """ 

4652 res = krb_as_req(upn=upn, ip=ip, key=key, password=password, **kwargs) 

4653 if not res: 

4654 return 

4655 

4656 return krb_tgs_req( 

4657 upn=res.upn, # UPN might get canonicalized 

4658 spn=spn, 

4659 sessionkey=res.sessionkey, 

4660 ticket=res.asrep.ticket, 

4661 ip=ip, 

4662 **kwargs, 

4663 ) 

4664 

4665 

4666def krb_get_salt(upn, ip=None, realm=None, host="WIN10", **kwargs): 

4667 """ 

4668 Kerberos AS-Req only to get the salt associated with the UPN. 

4669 """ 

4670 if realm is None: 

4671 _, realm = _parse_upn(upn) 

4672 cli = KerberosClient( 

4673 mode=KerberosClient.MODE.GET_SALT, 

4674 realm=realm, 

4675 ip=ip, 

4676 spn="krbtgt/" + realm, 

4677 upn=upn, 

4678 host=host, 

4679 **kwargs, 

4680 ) 

4681 cli.run() 

4682 cli.stop() 

4683 return cli.result 

4684 

4685 

4686def kpasswd( 

4687 upn, 

4688 targetupn=None, 

4689 ip=None, 

4690 password=None, 

4691 newpassword=None, 

4692 key=None, 

4693 ticket=None, 

4694 realm=None, 

4695 ssp=None, 

4696 setpassword=None, 

4697 timeout=3, 

4698 port=464, 

4699 debug=0, 

4700 **kwargs, 

4701): 

4702 """ 

4703 Change a password using RFC3244's Kerberos Set / Change Password. 

4704 

4705 :param upn: the UPN to use for authentication 

4706 :param targetupn: (optional) the UPN to change the password of. If not specified, 

4707 same as upn. 

4708 :param ip: the KDC ip. (optional. If not provided, Scapy will query the DNS for 

4709 _kerberos._tcp.dc._msdcs.domain.local). 

4710 :param key: (optional) pass the Key object. 

4711 :param ticket: (optional) a ticket to use. Either a TGT or ST for kadmin/changepw. 

4712 :param password: (optional) otherwise, pass the user's password 

4713 :param realm: (optional) the realm to use. Otherwise use the one from UPN. 

4714 :param setpassword: (optional) use "Set Password" mechanism. 

4715 :param ssp: (optional) a Kerberos SSP for the service kadmin/changepw@REALM. 

4716 If provided, you probably don't need anything else. Otherwise built. 

4717 """ 

4718 from scapy.layers.ldap import dclocator 

4719 

4720 if not realm: 

4721 _, realm = _parse_upn(upn) 

4722 spn = "kadmin/changepw@%s" % realm 

4723 if ip is None: 

4724 ip = dclocator( 

4725 realm, 

4726 timeout=timeout, 

4727 # Use connect mode instead of ldap for compatibility 

4728 # with MIT kerberos servers 

4729 mode="connect", 

4730 port=port, 

4731 debug=debug, 

4732 ).ip 

4733 if ssp is None and ticket is not None: 

4734 tktspn = ticket.getSPN().split("/")[0] 

4735 assert tktspn in ["krbtgt", "kadmin"], "Unexpected ticket type ! %s" % tktspn 

4736 if tktspn == "krbtgt": 

4737 log_runtime.info( 

4738 "Using 'Set Password' mode. This only works with admin privileges." 

4739 ) 

4740 setpassword = True 

4741 resp = krb_tgs_req( 

4742 upn=upn, 

4743 spn=spn, 

4744 ticket=ticket, 

4745 sessionkey=key, 

4746 ip=ip, 

4747 debug=debug, 

4748 ) 

4749 if resp is None: 

4750 return 

4751 ticket = resp.tgsrep.ticket 

4752 key = resp.sessionkey 

4753 if setpassword is None: 

4754 setpassword = bool(targetupn) 

4755 elif setpassword and targetupn is None: 

4756 targetupn = upn 

4757 assert setpassword or not targetupn, "Cannot use targetupn in changepassword mode !" 

4758 # Get a ticket for kadmin/changepw 

4759 if ssp is None: 

4760 if ticket is None: 

4761 # Get a ticket for kadmin/changepw through AS-REQ 

4762 resp = krb_as_req( 

4763 upn=upn, 

4764 spn=spn, 

4765 key=key, 

4766 ip=ip, 

4767 password=password, 

4768 debug=debug, 

4769 ) 

4770 if resp is None: 

4771 return 

4772 ticket = resp.asrep.ticket 

4773 key = resp.sessionkey 

4774 ssp = KerberosSSP( 

4775 UPN=upn, 

4776 SPN=spn, 

4777 ST=ticket, 

4778 KEY=key, 

4779 DC_IP=ip, 

4780 debug=debug, 

4781 **kwargs, 

4782 ) 

4783 Context, tok, status = ssp.GSS_Init_sec_context( 

4784 None, 

4785 req_flags=0, # No GSS_C_MUTUAL_FLAG 

4786 ) 

4787 if status != GSS_S_CONTINUE_NEEDED: 

4788 warning("SSP failed on initial GSS_Init_sec_context !") 

4789 if tok: 

4790 tok.show() 

4791 return 

4792 apreq = tok.innerToken.root 

4793 # Connect 

4794 sock = socket.socket() 

4795 sock.settimeout(timeout) 

4796 sock.connect((ip, port)) 

4797 sock = StreamSocket(sock, KpasswdTCPHeader) 

4798 # Do KPASSWD request 

4799 if newpassword is None: 

4800 try: 

4801 from prompt_toolkit import prompt 

4802 

4803 newpassword = prompt("Enter NEW password: ", is_password=True) 

4804 except ImportError: 

4805 newpassword = input("Enter NEW password: ") 

4806 krbpriv = KRB_PRIV(encPart=EncryptedData()) 

4807 krbpriv.encPart.encrypt( 

4808 Context.KrbSessionKey, 

4809 EncKrbPrivPart( 

4810 sAddress=HostAddress( 

4811 addrType=ASN1_INTEGER(2), # IPv4 

4812 address=ASN1_STRING(b"\xc0\xa8\x00e"), 

4813 ), 

4814 userData=ASN1_STRING( 

4815 bytes( 

4816 ChangePasswdData( 

4817 newpasswd=newpassword, 

4818 targname=PrincipalName.fromUPN(targetupn), 

4819 targrealm=realm, 

4820 ) 

4821 ) 

4822 if setpassword 

4823 else newpassword 

4824 ), 

4825 timestamp=None, 

4826 usec=None, 

4827 seqNumber=Context.SendSeqNum, 

4828 ), 

4829 ) 

4830 resp = sock.sr1( 

4831 KpasswdTCPHeader() 

4832 / KPASSWD_REQ( 

4833 pvno=0xFF80 if setpassword else 1, 

4834 apreq=apreq, 

4835 krbpriv=krbpriv, 

4836 ), 

4837 timeout=timeout, 

4838 verbose=0, 

4839 ) 

4840 # Verify KPASSWD response 

4841 if not resp: 

4842 raise TimeoutError("KPASSWD_REQ timed out !") 

4843 if KPASSWD_REP not in resp: 

4844 resp.show() 

4845 raise ValueError("Invalid response to KPASSWD_REQ !") 

4846 Context, tok, status = ssp.GSS_Init_sec_context( 

4847 Context, 

4848 input_token=resp.aprep, 

4849 ) 

4850 if status != GSS_S_COMPLETE: 

4851 warning("SSP failed on subsequent GSS_Init_sec_context !") 

4852 if tok: 

4853 tok.show() 

4854 return 

4855 # Parse answer KRB_PRIV 

4856 krbanswer = resp.krbpriv.encPart.decrypt(Context.KrbSessionKey) 

4857 userRep = KPasswdRepData(krbanswer.userData.val) 

4858 if userRep.resultCode != 0: 

4859 warning(userRep.sprintf("KPASSWD failed !")) 

4860 userRep.show() 

4861 return 

4862 print(userRep.sprintf("%resultCode%")) 

4863 

4864 

4865# SSP 

4866 

4867 

4868class KerberosSSP(SSP): 

4869 """ 

4870 The KerberosSSP 

4871 

4872 Client settings: 

4873 

4874 :param ST: the service ticket to use for access. 

4875 If not provided, will be retrieved 

4876 :param SPN: the SPN of the service to use. If not provided, will use the 

4877 target_name provided in the GSS_Init_sec_context 

4878 :param UPN: The client UPN 

4879 :param DC_IP: (optional) is ST+KEY are not provided, will need to contact 

4880 the KDC at this IP. If not provided, will perform dc locator. 

4881 :param TGT: (optional) pass a TGT to use to get the ST. 

4882 :param KEY: the session key associated with the ST if it is provided, 

4883 OR the session key associated with the TGT 

4884 OR the kerberos key associated with the UPN 

4885 :param PASSWORD: (optional) if a UPN is provided and not a KEY, this is the 

4886 password of the UPN. 

4887 :param U2U: (optional) use U2U when requesting the ST. 

4888 :param IAKERB: (optional) use IAKERB when requesting tickets. 

4889 

4890 Server settings: 

4891 

4892 :param SPN: the SPN of the service to use. 

4893 :param KEY: the kerberos key to use to decrypt the AP-req 

4894 :param UPN: (optional) the UPN, if used in U2U mode. 

4895 :param TGT: (optional) pass a TGT to use for U2U. 

4896 :param DC_IP: (optional) if TGT is not provided, request one on the KDC at 

4897 this IP using using the KEY when using U2U. 

4898 """ 

4899 

4900 auth_type = 0x10 

4901 

4902 class STATE(SSP.STATE): 

4903 INIT = 1 

4904 CLI_SENT_TGTREQ = 2 

4905 CLI_SENT_APREQ = 3 

4906 CLI_RCVD_APREP = 4 

4907 SRV_SENT_APREP = 5 

4908 FAILED = -1 

4909 

4910 class CONTEXT(SSP.CONTEXT): 

4911 __slots__ = [ 

4912 "SessionKey", 

4913 "ServerHostname", 

4914 "U2U", 

4915 "IAKERB", 

4916 "KrbSessionKey", # raw Key object 

4917 "ST", # the service ticket 

4918 "STSessionKey", # raw ST Key object (for DCE_STYLE) 

4919 "SeqNum", # for AP 

4920 "SendSeqNum", # for MIC 

4921 "RecvSeqNum", # for MIC 

4922 "IsAcceptor", 

4923 "SendSealKeyUsage", 

4924 "SendSignKeyUsage", 

4925 "RecvSealKeyUsage", 

4926 "RecvSignKeyUsage", 

4927 # server-only 

4928 "UPN", 

4929 "PAC", 

4930 # IAKERB 

4931 "IAKerbSocket", 

4932 ] 

4933 

4934 def __init__(self, IsAcceptor, req_flags=None): 

4935 self.state = KerberosSSP.STATE.INIT 

4936 self.SessionKey = None 

4937 self.ServerHostname = None 

4938 self.U2U = False 

4939 self.IAKERB = False 

4940 self.SendSeqNum = 0 

4941 self.RecvSeqNum = 0 

4942 self.KrbSessionKey = None 

4943 self.ST = None 

4944 self.STSessionKey = None 

4945 self.IsAcceptor = IsAcceptor 

4946 self.UPN = None 

4947 self.PAC = None 

4948 self.IAKerbSocket = None 

4949 # [RFC 4121] sect 2 

4950 if IsAcceptor: 

4951 self.SendSealKeyUsage = 22 

4952 self.SendSignKeyUsage = 23 

4953 self.RecvSealKeyUsage = 24 

4954 self.RecvSignKeyUsage = 25 

4955 else: 

4956 self.SendSealKeyUsage = 24 

4957 self.SendSignKeyUsage = 25 

4958 self.RecvSealKeyUsage = 22 

4959 self.RecvSignKeyUsage = 23 

4960 super(KerberosSSP.CONTEXT, self).__init__(req_flags=req_flags) 

4961 

4962 def clifailure(self): 

4963 self.__init__(self.IsAcceptor, req_flags=self.flags) 

4964 

4965 def __repr__(self): 

4966 if self.U2U: 

4967 return "KerberosSSP-U2U" 

4968 elif self.IAKERB: 

4969 return "KerberosSSP-IAKERB" 

4970 else: 

4971 return "KerberosSSP" 

4972 

4973 def __init__( 

4974 self, 

4975 ST=None, 

4976 UPN=None, 

4977 PASSWORD=None, 

4978 U2U=False, 

4979 IAKERB=False, 

4980 KEY=None, 

4981 SPN=None, 

4982 TGT=None, 

4983 DC_IP=None, 

4984 SKEY_TYPE=None, 

4985 debug=0, 

4986 **kwargs, 

4987 ): 

4988 import scapy.libs.rfc3961 # Trigger error if any # noqa: F401 

4989 

4990 self.ST = ST 

4991 self.UPN = UPN 

4992 self.KEY = KEY 

4993 self.SPN = SPN 

4994 self.TGT = TGT 

4995 self.TGTSessionKey = None 

4996 self.PASSWORD = PASSWORD 

4997 self.U2U = U2U 

4998 self.IAKERB = IAKERB 

4999 self.DC_IP = DC_IP 

5000 self.debug = debug 

5001 if SKEY_TYPE is None: 

5002 SKEY_TYPE = EncryptionType.AES128_CTS_HMAC_SHA1_96 

5003 self.SKEY_TYPE = SKEY_TYPE 

5004 super(KerberosSSP, self).__init__(**kwargs) 

5005 

5006 def __repr__(self): 

5007 if self.IAKERB: 

5008 return "<%s-IAKERB>" % self.__class__.__name__ 

5009 elif self.U2U: 

5010 return "<%s-U2U>" % self.__class__.__name__ 

5011 else: 

5012 return "<%s>" % self.__class__.__name__ 

5013 

5014 def GSS_Inquire_names_for_mech(self): 

5015 if self.IAKERB: 

5016 return ["1.3.6.1.5.2.5"] # Kerberos 5 - IAKERB 

5017 elif self.U2U: 

5018 return ["1.2.840.113554.1.2.2.3"] # Kerberos 5 - User to User 

5019 else: 

5020 return [ 

5021 "1.2.840.48018.1.2.2", # MS KRB5 - Microsoft Kerberos 5 

5022 "1.2.840.113554.1.2.2", # Kerberos 5 

5023 ] 

5024 

5025 def GSS_GetMICEx(self, Context, msgs, qop_req=0): 

5026 """ 

5027 [MS-KILE] sect 3.4.5.6 

5028 

5029 - AES: RFC4121 sect 4.2.6.1 

5030 """ 

5031 if Context.KrbSessionKey.etype in [17, 18]: # AES 

5032 # Concatenate the ToSign 

5033 ToSign = b"".join(x.data for x in msgs if x.sign) 

5034 sig = KRB_InnerToken( 

5035 TOK_ID=b"\x04\x04", 

5036 root=KRB_GSS_MIC( 

5037 Flags="AcceptorSubkey" 

5038 + ("+SentByAcceptor" if Context.IsAcceptor else ""), 

5039 SND_SEQ=Context.SendSeqNum, 

5040 ), 

5041 ) 

5042 ToSign += bytes(sig)[:16] 

5043 sig.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

5044 keyusage=Context.SendSignKeyUsage, 

5045 text=ToSign, 

5046 ) 

5047 else: 

5048 raise NotImplementedError 

5049 Context.SendSeqNum += 1 

5050 return sig 

5051 

5052 def GSS_VerifyMICEx(self, Context, msgs, signature): 

5053 """ 

5054 [MS-KILE] sect 3.4.5.7 

5055 

5056 - AES: RFC4121 sect 4.2.6.1 

5057 """ 

5058 Context.RecvSeqNum = signature.root.SND_SEQ 

5059 if Context.KrbSessionKey.etype in [17, 18]: # AES 

5060 # Concatenate the ToSign 

5061 ToSign = b"".join(x.data for x in msgs if x.sign) 

5062 ToSign += bytes(signature)[:16] 

5063 sig = Context.KrbSessionKey.make_checksum( 

5064 keyusage=Context.RecvSignKeyUsage, 

5065 text=ToSign, 

5066 ) 

5067 else: 

5068 raise NotImplementedError 

5069 if sig != signature.root.SGN_CKSUM: 

5070 raise ValueError("ERROR: Checksums don't match") 

5071 

5072 def GSS_WrapEx(self, Context, msgs, qop_req: GSS_QOP_REQ_FLAGS = 0): 

5073 """ 

5074 [MS-KILE] sect 3.4.5.4 

5075 

5076 - AES: RFC4121 sect 4.2.6.2 and [MS-KILE] sect 3.4.5.4.1 

5077 - HMAC-RC4: RFC4757 sect 7.3 and [MS-KILE] sect 3.4.5.4.1 

5078 """ 

5079 # Is confidentiality in use? 

5080 confidentiality = (Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG) and any( 

5081 x.conf_req_flag for x in msgs 

5082 ) 

5083 if Context.KrbSessionKey.etype in [17, 18]: # AES 

5084 # Build token 

5085 tok = KRB_InnerToken( 

5086 TOK_ID=b"\x05\x04", 

5087 root=KRB_GSS_Wrap( 

5088 Flags="AcceptorSubkey" 

5089 + ("+SentByAcceptor" if Context.IsAcceptor else "") 

5090 + ("+Sealed" if confidentiality else ""), 

5091 SND_SEQ=Context.SendSeqNum, 

5092 RRC=0, 

5093 ), 

5094 ) 

5095 Context.SendSeqNum += 1 

5096 # Real separation starts now: RFC4121 sect 4.2.4 

5097 if confidentiality: 

5098 # Confidentiality is requested (see RFC4121 sect 4.3) 

5099 # {"header" | encrypt(plaintext-data | filler | "header")} 

5100 # 0. Roll confounder 

5101 Confounder = os.urandom(Context.KrbSessionKey.ep.blocksize) 

5102 # 1. Concatenate the data to be encrypted 

5103 Data = b"".join(x.data for x in msgs if x.conf_req_flag) 

5104 DataLen = len(Data) 

5105 # 2. Add filler 

5106 if qop_req & GSS_QOP_REQ_FLAGS.GSS_S_NO_SECBUFFER_PADDING: 

5107 # Special case for compatibility with Windows API. See 

5108 # GSS_QOP_REQ_FLAGS. 

5109 tok.root.EC = 0 

5110 else: 

5111 # [MS-KILE] sect 3.4.5.4.1 - "For AES-SHA1 ciphers, the EC must not 

5112 # be zero" 

5113 tok.root.EC = ( 

5114 (-DataLen) % Context.KrbSessionKey.ep.blocksize 

5115 ) or 16 

5116 Filler = b"\x00" * tok.root.EC 

5117 Data += Filler 

5118 # 3. Add first 16 octets of the Wrap token "header" 

5119 PlainHeader = bytes(tok)[:16] 

5120 Data += PlainHeader 

5121 # 4. Build 'ToSign', exclusively used for checksum 

5122 ToSign = Confounder 

5123 ToSign += b"".join(x.data for x in msgs if x.sign) 

5124 ToSign += Filler 

5125 ToSign += PlainHeader 

5126 # 5. Finalize token for signing 

5127 # "The RRC field is [...] 28 if encryption is requested." 

5128 tok.root.RRC = 28 

5129 # 6. encrypt() is the encryption operation (which provides for 

5130 # integrity protection) 

5131 Data = Context.KrbSessionKey.encrypt( 

5132 keyusage=Context.SendSealKeyUsage, 

5133 plaintext=Data, 

5134 confounder=Confounder, 

5135 signtext=ToSign, 

5136 ) 

5137 # 7. Rotate 

5138 Data = strrot(Data, tok.root.RRC + tok.root.EC) 

5139 # 8. Split (token and encrypted messages) 

5140 toklen = len(Data) - DataLen 

5141 tok.root.Data = Data[:toklen] 

5142 offset = toklen 

5143 for msg in msgs: 

5144 msglen = len(msg.data) 

5145 if msg.conf_req_flag: 

5146 msg.data = Data[offset : offset + msglen] 

5147 offset += msglen 

5148 return msgs, tok 

5149 else: 

5150 # No confidentiality is requested 

5151 # {"header" | plaintext-data | get_mic(plaintext-data | "header")} 

5152 # 0. Concatenate the data 

5153 Data = b"".join(x.data for x in msgs if x.sign) 

5154 DataLen = len(Data) 

5155 # 1. Add first 16 octets of the Wrap token "header" 

5156 ToSign = Data 

5157 ToSign += bytes(tok)[:16] 

5158 # 2. get_mic() is the checksum operation for the required 

5159 # checksum mechanism 

5160 Mic = Context.KrbSessionKey.make_checksum( 

5161 keyusage=Context.SendSealKeyUsage, 

5162 text=ToSign, 

5163 ) 

5164 # In Wrap tokens without confidentiality, the EC field SHALL be used 

5165 # to encode the number of octets in the trailing checksum 

5166 tok.root.EC = 12 # len(tok.root.Data) == 12 for AES 

5167 # "The RRC field ([RFC4121] section 4.2.5) is 12 if no encryption 

5168 # is requested" 

5169 tok.root.RRC = 12 

5170 # 3. Concat and pack 

5171 for msg in msgs: 

5172 if msg.sign: 

5173 msg.data = b"" 

5174 Data = Data + Mic 

5175 # 4. Rotate 

5176 tok.root.Data = strrot(Data, tok.root.RRC) 

5177 return msgs, tok 

5178 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

5179 # Build token 

5180 seq = struct.pack(">I", Context.SendSeqNum) 

5181 tok = KRB_InnerToken( 

5182 TOK_ID=b"\x02\x01", 

5183 root=KRB_GSS_Wrap_RFC1964( 

5184 SGN_ALG="HMAC", 

5185 SEAL_ALG="RC4" if confidentiality else "none", 

5186 SND_SEQ=seq 

5187 + ( 

5188 # See errata 

5189 b"\xff\xff\xff\xff" 

5190 if Context.IsAcceptor 

5191 else b"\x00\x00\x00\x00" 

5192 ), 

5193 ), 

5194 ) 

5195 Context.SendSeqNum += 1 

5196 # 0. Concatenate data 

5197 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

5198 ToEncrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

5199 Kss = Context.KrbSessionKey.key 

5200 # 1. Roll confounder 

5201 Confounder = os.urandom(8) 

5202 # 2. Compute the 'Kseq' key 

5203 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

5204 if Context.KrbSessionKey.etype == 24: # EXP 

5205 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5206 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

5207 else: 

5208 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

5209 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

5210 # 3. Build SGN_CKSUM 

5211 tok.root.SGN_CKSUM = Context.KrbSessionKey.make_checksum( 

5212 keyusage=13, # See errata 

5213 text=bytes(tok)[:8] + Confounder + ToSign, 

5214 )[:8] 

5215 # 4. Populate token + encrypt 

5216 if confidentiality: 

5217 # 'encrypt' is requested 

5218 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

5219 tok.root.CONFOUNDER = rc4.update(Confounder) 

5220 Data = rc4.update(ToEncrypt) 

5221 # Split encrypted data 

5222 offset = 0 

5223 for msg in msgs: 

5224 msglen = len(msg.data) 

5225 if msg.conf_req_flag: 

5226 msg.data = Data[offset : offset + msglen] 

5227 offset += msglen 

5228 else: 

5229 # 'encrypt' is not requested 

5230 tok.root.CONFOUNDER = Confounder 

5231 # 5. Compute the 'Kseq' key 

5232 if Context.KrbSessionKey.etype == 24: # EXP 

5233 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5234 Kseq = Kseq[:7] + b"\xab" * 9 

5235 else: 

5236 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

5237 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

5238 # 6. Encrypt 'SND_SEQ' 

5239 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

5240 tok.root.SND_SEQ = rc4.update(tok.root.SND_SEQ) 

5241 # 7. Include 'InitialContextToken pseudo ASN.1 header' 

5242 tok = KRB_GSSAPI_Token( 

5243 MechType="1.2.840.113554.1.2.2", # Kerberos 5 

5244 innerToken=tok, 

5245 ) 

5246 return msgs, tok 

5247 else: 

5248 raise NotImplementedError 

5249 

5250 def GSS_UnwrapEx(self, Context, msgs, signature): 

5251 """ 

5252 [MS-KILE] sect 3.4.5.5 

5253 

5254 - AES: RFC4121 sect 4.2.6.2 

5255 - HMAC-RC4: RFC4757 sect 7.3 

5256 """ 

5257 if Context.KrbSessionKey.etype in [17, 18]: # AES 

5258 confidentiality = signature.root.Flags.Sealed 

5259 # Real separation starts now: RFC4121 sect 4.2.4 

5260 if confidentiality: 

5261 # 0. Concatenate the data 

5262 Data = signature.root.Data 

5263 Data += b"".join(x.data for x in msgs if x.conf_req_flag) 

5264 # 1. Un-Rotate 

5265 Data = strrot(Data, signature.root.RRC + signature.root.EC, right=False) 

5266 

5267 # 2. Function to build 'ToSign', exclusively used for checksum 

5268 def MakeToSign(Confounder, DecText): 

5269 offset = 0 

5270 # 2.a Confounder 

5271 ToSign = Confounder 

5272 # 2.b Messages 

5273 for msg in msgs: 

5274 msglen = len(msg.data) 

5275 if msg.conf_req_flag: 

5276 ToSign += DecText[offset : offset + msglen] 

5277 offset += msglen 

5278 elif msg.sign: 

5279 ToSign += msg.data 

5280 # 2.c Filler & Padding 

5281 ToSign += DecText[offset:] 

5282 return ToSign 

5283 

5284 # 3. Decrypt 

5285 Data = Context.KrbSessionKey.decrypt( 

5286 keyusage=Context.RecvSealKeyUsage, 

5287 ciphertext=Data, 

5288 presignfunc=MakeToSign, 

5289 ) 

5290 # 4. Split 

5291 Data, f16header = ( 

5292 Data[:-16], 

5293 Data[-16:], 

5294 ) 

5295 # 5. Check header 

5296 hdr = signature.copy() 

5297 hdr.root.RRC = 0 

5298 if f16header != bytes(hdr)[:16]: 

5299 raise ValueError("ERROR: Headers don't match") 

5300 # 6. Split (and ignore filler) 

5301 offset = 0 

5302 for msg in msgs: 

5303 msglen = len(msg.data) 

5304 if msg.conf_req_flag: 

5305 msg.data = Data[offset : offset + msglen] 

5306 offset += msglen 

5307 # Case without msgs 

5308 if len(msgs) == 1 and not msgs[0].data: 

5309 msgs[0].data = Data 

5310 return msgs 

5311 else: 

5312 # No confidentiality is requested 

5313 # 0. Concatenate the data 

5314 Data = signature.root.Data 

5315 Data += b"".join(x.data for x in msgs if x.sign) 

5316 # 1. Un-Rotate 

5317 Data = strrot(Data, signature.root.RRC, right=False) 

5318 # 2. Split 

5319 Data, Mic = Data[: -signature.root.EC], Data[-signature.root.EC :] 

5320 # "Both the EC field and the RRC field in 

5321 # the token header SHALL be filled with zeroes for the purpose of 

5322 # calculating the checksum." 

5323 ToSign = Data 

5324 hdr = signature.copy() 

5325 hdr.root.RRC = 0 

5326 hdr.root.EC = 0 

5327 # Concatenate the data 

5328 ToSign += bytes(hdr)[:16] 

5329 # 3. Calculate the signature 

5330 sig = Context.KrbSessionKey.make_checksum( 

5331 keyusage=Context.RecvSealKeyUsage, 

5332 text=ToSign, 

5333 ) 

5334 # 4. Compare 

5335 if sig != Mic: 

5336 raise ValueError("ERROR: Checksums don't match") 

5337 # Case without msgs 

5338 if len(msgs) == 1 and not msgs[0].data: 

5339 msgs[0].data = Data 

5340 return msgs 

5341 elif Context.KrbSessionKey.etype in [23, 24]: # RC4 

5342 # Drop wrapping 

5343 tok = signature.innerToken 

5344 

5345 # Detect confidentiality 

5346 confidentiality = tok.root.SEAL_ALG != 0xFFFF 

5347 

5348 # 0. Concatenate data 

5349 ToDecrypt = b"".join(x.data for x in msgs if x.conf_req_flag) 

5350 Kss = Context.KrbSessionKey.key 

5351 # 1. Compute the 'Kseq' key 

5352 if Context.KrbSessionKey.etype == 24: # EXP 

5353 Kseq = Hmac_MD5(Kss).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5354 Kseq = Kseq[:7] + b"\xab" * 9 

5355 else: 

5356 Kseq = Hmac_MD5(Kss).digest(b"\x00\x00\x00\x00") 

5357 Kseq = Hmac_MD5(Kseq).digest(tok.root.SGN_CKSUM) 

5358 # 2. Decrypt 'SND_SEQ' 

5359 rc4 = Cipher(decrepit_algorithms.ARC4(Kseq), mode=None).encryptor() 

5360 seq = rc4.update(tok.root.SND_SEQ)[:4] 

5361 # 3. Compute the 'Kcrypt' key 

5362 Klocal = strxor(Kss, len(Kss) * b"\xf0") 

5363 if Context.KrbSessionKey.etype == 24: # EXP 

5364 Kcrypt = Hmac_MD5(Klocal).digest(b"fortybits\x00" + b"\x00\x00\x00\x00") 

5365 Kcrypt = Kcrypt[:7] + b"\xab" * 9 

5366 else: 

5367 Kcrypt = Hmac_MD5(Klocal).digest(b"\x00\x00\x00\x00") 

5368 Kcrypt = Hmac_MD5(Kcrypt).digest(seq) 

5369 # 4. Decrypt 

5370 if confidentiality: 

5371 # 'encrypt' was requested 

5372 rc4 = Cipher(decrepit_algorithms.ARC4(Kcrypt), mode=None).encryptor() 

5373 Confounder = rc4.update(tok.root.CONFOUNDER) 

5374 Data = rc4.update(ToDecrypt) 

5375 # Split encrypted data 

5376 offset = 0 

5377 for msg in msgs: 

5378 msglen = len(msg.data) 

5379 if msg.conf_req_flag: 

5380 msg.data = Data[offset : offset + msglen] 

5381 offset += msglen 

5382 else: 

5383 # 'encrypt' was not requested 

5384 Confounder = tok.root.CONFOUNDER 

5385 # 5. Verify SGN_CKSUM 

5386 ToSign = _rfc1964pad(b"".join(x.data for x in msgs if x.sign)) 

5387 Context.KrbSessionKey.verify_checksum( 

5388 keyusage=13, # See errata 

5389 text=bytes(tok)[:8] + Confounder + ToSign, 

5390 cksum=tok.root.SGN_CKSUM, 

5391 ) 

5392 return msgs 

5393 else: 

5394 raise NotImplementedError 

5395 

5396 def GSS_Init_sec_context( 

5397 self, 

5398 Context: CONTEXT, 

5399 input_token=None, 

5400 target_name: Optional[str] = None, 

5401 req_flags: Optional[GSS_C_FLAGS] = None, 

5402 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5403 ): 

5404 if Context is None: 

5405 # New context 

5406 Context = self.CONTEXT(IsAcceptor=False, req_flags=req_flags) 

5407 

5408 if self.IAKERB: 

5409 # IAKERB - We return asynchronously either packets from this 

5410 # GSS_Init_sec_context, or whatever packet are wrapped when talking to 

5411 # the server. 

5412 if Context.IAKerbSocket is None: 

5413 # Initial call: create a IAKerbSocket and a thread 

5414 _, crealm = _parse_upn(self.UPN) 

5415 Context.IAKERB = True 

5416 Context.IAKerbSocket = IAKerbSocket( 

5417 Context=Context, 

5418 realm=crealm, 

5419 ) 

5420 

5421 # Run in the background 

5422 Context.IAKerbSocket.run( 

5423 self.GSS_Init_sec_context, 

5424 Context=Context, 

5425 input_token=input_token, 

5426 target_name=target_name, 

5427 req_flags=req_flags, 

5428 chan_bindings=chan_bindings, 

5429 ) 

5430 

5431 return Context.IAKerbSocket.next() 

5432 elif input_token is not None: 

5433 # Intermediate token: let the thread handle it. 

5434 iakerb = Context.IAKerbSocket.unpack(input_token) 

5435 if iakerb: 

5436 # This is a IAKERB token 

5437 return Context.IAKerbSocket.next(iakerb) 

5438 

5439 # Else, continue. This is not an IAKERB token. 

5440 

5441 if Context.state == self.STATE.INIT and self.U2U: 

5442 # U2U - Get TGT 

5443 Context.state = self.STATE.CLI_SENT_TGTREQ 

5444 return ( 

5445 Context, 

5446 KRB_GSSAPI_Token( 

5447 MechType="1.2.840.113554.1.2.2.3", # U2U 

5448 innerToken=KRB_InnerToken( 

5449 TOK_ID=b"\x04\x00", 

5450 root=KRB_TGT_REQ(), 

5451 ), 

5452 ), 

5453 GSS_S_CONTINUE_NEEDED, 

5454 ) 

5455 

5456 if Context.state in [self.STATE.INIT, self.STATE.CLI_SENT_TGTREQ]: 

5457 if not self.UPN: 

5458 raise ValueError("Missing UPN attribute") 

5459 

5460 # Do we have a ST? 

5461 if self.ST is None: 

5462 # Client sends an AP-req 

5463 if not self.SPN and not target_name: 

5464 raise ValueError("Missing SPN/target_name attribute") 

5465 

5466 additional_tickets = [] 

5467 if self.U2U: 

5468 try: 

5469 # GSSAPI / Kerberos 

5470 tgt_rep = input_token.root.innerToken.root 

5471 except AttributeError: 

5472 try: 

5473 # Kerberos 

5474 tgt_rep = input_token.innerToken.root 

5475 except AttributeError: 

5476 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5477 if not isinstance(tgt_rep, KRB_TGT_REP): 

5478 tgt_rep.show() 

5479 raise ValueError("KerberosSSP: Unexpected input_token !") 

5480 additional_tickets = [tgt_rep.ticket] 

5481 

5482 try: 

5483 if self.TGT is None: 

5484 # Get TGT. We were passed a kerberos key 

5485 res = krb_as_req( 

5486 upn=self.UPN, 

5487 ip=self.DC_IP, 

5488 key=self.KEY, 

5489 password=self.PASSWORD, 

5490 debug=self.debug, 

5491 verbose=bool(self.debug), 

5492 iakerb=self.IAKERB, 

5493 iakerb_socket=Context.IAKerbSocket, 

5494 ) 

5495 if res is None: 

5496 # Failed to retrieve the ticket 

5497 return Context, None, GSS_S_FAILURE 

5498 

5499 # Update UPN (could have been canonicalized) 

5500 self.UPN = res.upn 

5501 

5502 # Store TGT, 

5503 self.TGT = res.asrep.ticket 

5504 self.TGTSessionKey = res.sessionkey 

5505 elif self.TGTSessionKey is None: 

5506 # We have a TGT and were passed its key 

5507 self.TGTSessionKey = self.KEY 

5508 

5509 # Get ST 

5510 if not self.TGTSessionKey: 

5511 raise ValueError("Cannot use TGT without the KEY") 

5512 

5513 res = krb_tgs_req( 

5514 upn=self.UPN, 

5515 spn=self.SPN or target_name, 

5516 ip=self.DC_IP, 

5517 sessionkey=self.TGTSessionKey, 

5518 ticket=self.TGT, 

5519 additional_tickets=additional_tickets, 

5520 u2u=self.U2U, 

5521 debug=self.debug, 

5522 verbose=bool(self.debug), 

5523 iakerb=self.IAKERB, 

5524 iakerb_socket=Context.IAKerbSocket, 

5525 ) 

5526 if not res: 

5527 # Failed to retrieve the ticket 

5528 return Context, None, GSS_S_FAILURE 

5529 except TimeoutError: 

5530 # We couldn't reach the DC to get a ticket. Fail KerberosSSP. 

5531 return Context, None, GSS_S_BAD_MECH 

5532 

5533 # Store the service ticket and associated key 

5534 Context.ST, Context.STSessionKey = res.tgsrep.ticket, res.sessionkey 

5535 elif not self.KEY: 

5536 raise ValueError("Must provide KEY with ST") 

5537 else: 

5538 # We were passed a ST and its key 

5539 Context.ST = self.ST 

5540 Context.STSessionKey = self.KEY 

5541 

5542 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5543 raise ValueError( 

5544 "Cannot use GSS_C_DELEG_FLAG when passed a service ticket !" 

5545 ) 

5546 

5547 # Save ServerHostname 

5548 if len(Context.ST.sname.nameString) == 2: 

5549 Context.ServerHostname = Context.ST.sname.nameString[1].val.decode() 

5550 

5551 # Build the KRB-AP 

5552 apOptions = ASN1_BIT_STRING("000") 

5553 if Context.flags & GSS_C_FLAGS.GSS_C_MUTUAL_FLAG: 

5554 apOptions.set(2, "1") # mutual-required 

5555 if self.U2U: 

5556 apOptions.set(1, "1") # use-session-key 

5557 Context.U2U = True 

5558 ap_req = KRB_AP_REQ( 

5559 apOptions=apOptions, 

5560 ticket=Context.ST, 

5561 authenticator=EncryptedData(), 

5562 ) 

5563 

5564 # Get the current time 

5565 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5566 # Pick a random session key 

5567 Context.KrbSessionKey = Key.new_random_key( 

5568 self.SKEY_TYPE, 

5569 ) 

5570 

5571 # We use a random SendSeqNum 

5572 Context.SendSeqNum = RandNum(0, 0x7FFFFFFF)._fix() 

5573 

5574 # Get the realm of the client 

5575 _, crealm = _parse_upn(self.UPN) 

5576 

5577 # Build the RFC4121 authenticator checksum 

5578 authenticator_checksum = KRB_AuthenticatorChecksum( 

5579 # RFC 4121 sect 4.1.1.2 

5580 # "The Bnd field contains the MD5 hash of channel bindings" 

5581 Bnd=( 

5582 chan_bindings.digestMD5() 

5583 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5584 else (b"\x00" * 16) 

5585 ), 

5586 Flags=int(Context.flags), 

5587 ) 

5588 

5589 if Context.flags & GSS_C_FLAGS.GSS_C_DELEG_FLAG: 

5590 # Delegate TGT 

5591 raise NotImplementedError("GSS_C_DELEG_FLAG is not implemented !") 

5592 # authenticator_checksum.Deleg = KRB_CRED( 

5593 # tickets=[self.TGT], 

5594 # encPart=EncryptedData() 

5595 # ) 

5596 # authenticator_checksum.encPart.encrypt( 

5597 # Context.STSessionKey, 

5598 # EncKrbCredPart( 

5599 # ticketInfo=KrbCredInfo( 

5600 # key=EncryptionKey.fromKey(self.TGTSessionKey), 

5601 # prealm=ASN1_GENERAL_STRING(crealm), 

5602 # pname=PrincipalName.fromUPN(self.UPN), 

5603 # # TODO: rework API to pass starttime... here. 

5604 # sreralm=self.TGT.realm, 

5605 # sname=self.TGT.sname, 

5606 # ) 

5607 # ) 

5608 # ) 

5609 

5610 # Build and encrypt the full KRB_Authenticator 

5611 ap_req.authenticator.encrypt( 

5612 Context.STSessionKey, 

5613 KRB_Authenticator( 

5614 crealm=crealm, 

5615 cname=PrincipalName.fromUPN(self.UPN), 

5616 cksum=Checksum( 

5617 cksumtype="KRB-AUTHENTICATOR", checksum=authenticator_checksum 

5618 ), 

5619 ctime=ASN1_GENERALIZED_TIME(now_time), 

5620 cusec=ASN1_INTEGER(0), 

5621 subkey=EncryptionKey.fromKey(Context.KrbSessionKey), 

5622 seqNumber=Context.SendSeqNum, 

5623 encAuthorizationData=AuthorizationData( 

5624 seq=[ 

5625 AuthorizationDataItem( 

5626 adType="AD-IF-RELEVANT", 

5627 adData=AuthorizationData( 

5628 seq=[ 

5629 AuthorizationDataItem( 

5630 adType="KERB-AUTH-DATA-TOKEN-RESTRICTIONS", 

5631 adData=KERB_AD_RESTRICTION_ENTRY( 

5632 restriction=LSAP_TOKEN_INFO_INTEGRITY( 

5633 MachineID=bytes(RandBin(32)), 

5634 PermanentMachineID=bytes( 

5635 RandBin(32) 

5636 ), 

5637 ) 

5638 ), 

5639 ), 

5640 # This isn't documented, but sent on Windows :/ 

5641 AuthorizationDataItem( 

5642 adType="KERB-LOCAL", 

5643 adData=b"\x00" * 16, 

5644 ), 

5645 ] 

5646 + ( 

5647 # Channel bindings 

5648 [ 

5649 AuthorizationDataItem( 

5650 adType="AD-AUTH-DATA-AP-OPTIONS", 

5651 adData=KERB_AUTH_DATA_AP_OPTIONS( 

5652 apOptions="KERB_AP_OPTIONS_CBT" 

5653 ), 

5654 ) 

5655 ] 

5656 if chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5657 else [] 

5658 ) 

5659 ), 

5660 ) 

5661 ] 

5662 ), 

5663 ), 

5664 ) 

5665 Context.state = self.STATE.CLI_SENT_APREQ 

5666 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5667 # Raw kerberos DCE-STYLE 

5668 return Context, ap_req, GSS_S_CONTINUE_NEEDED 

5669 else: 

5670 # Kerberos wrapper 

5671 return ( 

5672 Context, 

5673 KRB_GSSAPI_Token( 

5674 innerToken=KRB_InnerToken( 

5675 root=ap_req, 

5676 ) 

5677 ), 

5678 GSS_S_CONTINUE_NEEDED, 

5679 ) 

5680 

5681 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5682 if isinstance(input_token, KRB_AP_REP): 

5683 # Raw AP_REP was passed 

5684 ap_rep = input_token 

5685 else: 

5686 try: 

5687 # GSSAPI / Kerberos 

5688 ap_rep = input_token.root.innerToken.root 

5689 except AttributeError: 

5690 try: 

5691 # Kerberos 

5692 ap_rep = input_token.innerToken.root 

5693 except AttributeError: 

5694 try: 

5695 # Raw kerberos DCE-STYLE 

5696 ap_rep = input_token.root 

5697 except AttributeError: 

5698 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5699 if not isinstance(ap_rep, KRB_AP_REP): 

5700 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5701 

5702 # Retrieve SessionKey 

5703 repPart = ap_rep.encPart.decrypt(Context.STSessionKey) 

5704 if repPart.subkey is not None: 

5705 Context.SessionKey = repPart.subkey.keyvalue.val 

5706 Context.KrbSessionKey = repPart.subkey.toKey() 

5707 

5708 # OK ! 

5709 Context.state = self.STATE.CLI_RCVD_APREP 

5710 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5711 # [MS-KILE] sect 3.4.5.1 

5712 # The client MUST generate an additional AP exchange reply message 

5713 # exactly as the server would as the final message to send to the 

5714 # server. 

5715 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5716 cli_ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5717 cli_ap_rep.encPart.encrypt( 

5718 Context.STSessionKey, 

5719 EncAPRepPart( 

5720 ctime=ASN1_GENERALIZED_TIME(now_time), 

5721 seqNumber=repPart.seqNumber, 

5722 subkey=None, 

5723 ), 

5724 ) 

5725 return Context, cli_ap_rep, GSS_S_COMPLETE 

5726 return Context, None, GSS_S_COMPLETE 

5727 elif ( 

5728 Context.state == self.STATE.CLI_RCVD_APREP 

5729 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5730 ): 

5731 # DCE_STYLE with SPNEGOSSP 

5732 return Context, None, GSS_S_COMPLETE 

5733 else: 

5734 raise ValueError("KerberosSSP: Unknown state") 

5735 

5736 def GSS_Accept_sec_context( 

5737 self, 

5738 Context: CONTEXT, 

5739 input_token=None, 

5740 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5741 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

5742 ): 

5743 if Context is None: 

5744 # New context 

5745 Context = self.CONTEXT(IsAcceptor=True, req_flags=req_flags) 

5746 

5747 import scapy.layers.msrpce.mspac # noqa: F401 

5748 

5749 if Context.state == self.STATE.INIT: 

5750 if self.UPN and self.SPN: 

5751 raise ValueError("Cannot use SPN and UPN at the same time !") 

5752 if self.SPN and self.TGT: 

5753 raise ValueError("Cannot use TGT with SPN.") 

5754 if self.UPN and not self.TGT: 

5755 # UPN is provided: use U2U 

5756 res = krb_as_req( 

5757 self.UPN, 

5758 self.DC_IP, 

5759 key=self.KEY, 

5760 password=self.PASSWORD, 

5761 ) 

5762 self.TGT, self.TGTSessionKey = res.asrep.ticket, res.sessionkey 

5763 

5764 # Server receives AP-req, sends AP-rep 

5765 if isinstance(input_token, KRB_AP_REQ): 

5766 # Raw AP_REQ was passed 

5767 ap_req = input_token 

5768 else: 

5769 try: 

5770 # GSSAPI/Kerberos 

5771 ap_req = input_token.root.innerToken.root 

5772 except AttributeError: 

5773 try: 

5774 # Kerberos 

5775 ap_req = input_token.innerToken.root 

5776 except AttributeError: 

5777 try: 

5778 # Raw kerberos 

5779 ap_req = input_token.root 

5780 except AttributeError: 

5781 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5782 

5783 if isinstance(ap_req, KRB_TGT_REQ): 

5784 # Special U2U case 

5785 Context.U2U = True 

5786 return ( 

5787 None, 

5788 KRB_GSSAPI_Token( 

5789 MechType="1.2.840.113554.1.2.2.3", # U2U 

5790 innerToken=KRB_InnerToken( 

5791 TOK_ID=b"\x04\x01", 

5792 root=KRB_TGT_REP( 

5793 ticket=self.TGT, 

5794 ), 

5795 ), 

5796 ), 

5797 GSS_S_CONTINUE_NEEDED, 

5798 ) 

5799 elif not isinstance(ap_req, KRB_AP_REQ): 

5800 ap_req.show() 

5801 raise ValueError("Unexpected type in KerberosSSP") 

5802 if not self.KEY: 

5803 raise ValueError("Missing KEY attribute") 

5804 

5805 now_time = datetime.now(timezone.utc).replace(microsecond=0) 

5806 

5807 # If using a UPN, require U2U 

5808 if self.UPN and ap_req.apOptions.val[1] != "1": # use-session-key 

5809 # Required but not provided. Return an error 

5810 Context.U2U = True 

5811 err = KRB_GSSAPI_Token( 

5812 innerToken=KRB_InnerToken( 

5813 TOK_ID=b"\x03\x00", 

5814 root=KRB_ERROR( 

5815 errorCode="KRB_AP_ERR_USER_TO_USER_REQUIRED", 

5816 stime=ASN1_GENERALIZED_TIME(now_time), 

5817 realm=ap_req.ticket.realm, 

5818 sname=ap_req.ticket.sname, 

5819 eData=KRB_TGT_REP( 

5820 ticket=self.TGT, 

5821 ), 

5822 ), 

5823 ) 

5824 ) 

5825 return Context, err, GSS_S_CONTINUE_NEEDED 

5826 

5827 # Validate the 'serverName' of the ticket. 

5828 sname = ap_req.ticket.getSPN() 

5829 our_sname = self.SPN or self.UPN 

5830 if not _spn_are_equal(our_sname, sname): 

5831 warning("KerberosSSP: bad server name: %s != %s" % (sname, our_sname)) 

5832 err = KRB_GSSAPI_Token( 

5833 innerToken=KRB_InnerToken( 

5834 TOK_ID=b"\x03\x00", 

5835 root=KRB_ERROR( 

5836 errorCode="KRB_AP_ERR_BADMATCH", 

5837 stime=ASN1_GENERALIZED_TIME(now_time), 

5838 realm=ap_req.ticket.realm, 

5839 sname=ap_req.ticket.sname, 

5840 eData=None, 

5841 ), 

5842 ) 

5843 ) 

5844 return Context, err, GSS_S_BAD_MECH 

5845 

5846 # Decrypt the ticket 

5847 try: 

5848 tkt = ap_req.ticket.encPart.decrypt(self.KEY) 

5849 except ValueError as ex: 

5850 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5851 err = KRB_GSSAPI_Token( 

5852 innerToken=KRB_InnerToken( 

5853 TOK_ID=b"\x03\x00", 

5854 root=KRB_ERROR( 

5855 errorCode="KRB_AP_ERR_MODIFIED", 

5856 stime=ASN1_GENERALIZED_TIME(now_time), 

5857 realm=ap_req.ticket.realm, 

5858 sname=ap_req.ticket.sname, 

5859 eData=None, 

5860 ), 

5861 ) 

5862 ) 

5863 return Context, err, GSS_S_DEFECTIVE_CREDENTIAL 

5864 

5865 # Store information about the user in the Context 

5866 if tkt.authorizationData and tkt.authorizationData.seq: 

5867 # Get AD-IF-RELEVANT 

5868 adIfRelevant = tkt.authorizationData.getAuthData(0x1) 

5869 if adIfRelevant: 

5870 # Get AD-WIN2K-PAC 

5871 Context.PAC = adIfRelevant.getAuthData(0x80) 

5872 

5873 # Get AP-REQ session key 

5874 Context.STSessionKey = tkt.key.toKey() 

5875 authenticator = ap_req.authenticator.decrypt(Context.STSessionKey) 

5876 

5877 # Compute an application session key ([MS-KILE] sect 3.1.1.2) 

5878 subkey = None 

5879 if ap_req.apOptions.val[2] == "1": # mutual-required 

5880 appkey = Key.new_random_key( 

5881 self.SKEY_TYPE, 

5882 ) 

5883 Context.KrbSessionKey = appkey 

5884 Context.SessionKey = appkey.key 

5885 subkey = EncryptionKey.fromKey(appkey) 

5886 else: 

5887 Context.KrbSessionKey = self.KEY 

5888 Context.SessionKey = self.KEY.key 

5889 

5890 # Eventually process the "checksum" 

5891 if authenticator.cksum and authenticator.cksum.cksumtype == 0x8003: 

5892 # KRB-Authenticator 

5893 authcksum = authenticator.cksum.checksum 

5894 Context.flags = authcksum.Flags 

5895 # Check channel bindings 

5896 if ( 

5897 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5898 and chan_bindings.digestMD5() != authcksum.Bnd 

5899 and not ( 

5900 GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS in req_flags 

5901 and authcksum.Bnd == GSS_C_NO_CHANNEL_BINDINGS 

5902 ) 

5903 ): 

5904 # Channel binding checks failed. 

5905 return Context, None, GSS_S_BAD_BINDINGS 

5906 elif ( 

5907 chan_bindings != GSS_C_NO_CHANNEL_BINDINGS 

5908 and GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS not in req_flags 

5909 ): 

5910 # Uhoh, we required channel bindings 

5911 return Context, None, GSS_S_BAD_BINDINGS 

5912 

5913 # Build response (RFC4120 sect 3.2.4) 

5914 ap_rep = KRB_AP_REP(encPart=EncryptedData()) 

5915 ap_rep.encPart.encrypt( 

5916 Context.STSessionKey, 

5917 EncAPRepPart( 

5918 ctime=authenticator.ctime, 

5919 cusec=authenticator.cusec, 

5920 seqNumber=None, 

5921 subkey=subkey, 

5922 ), 

5923 ) 

5924 Context.state = self.STATE.SRV_SENT_APREP 

5925 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5926 # [MS-KILE] sect 3.4.5.1 

5927 return Context, ap_rep, GSS_S_CONTINUE_NEEDED 

5928 return Context, ap_rep, GSS_S_COMPLETE # success 

5929 elif ( 

5930 Context.state == self.STATE.SRV_SENT_APREP 

5931 and Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5932 ): 

5933 # [MS-KILE] sect 3.4.5.1 

5934 # The server MUST receive the additional AP exchange reply message and 

5935 # verify that the message is constructed correctly. 

5936 if not input_token: 

5937 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5938 # Server receives AP-req, sends AP-rep 

5939 if isinstance(input_token, KRB_AP_REP): 

5940 # Raw AP_REP was passed 

5941 ap_rep = input_token 

5942 else: 

5943 try: 

5944 # GSSAPI/Kerberos 

5945 ap_rep = input_token.root.innerToken.root 

5946 except AttributeError: 

5947 try: 

5948 # Raw Kerberos 

5949 ap_rep = input_token.root 

5950 except AttributeError: 

5951 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5952 # Decrypt the AP-REP 

5953 try: 

5954 ap_rep.encPart.decrypt(Context.STSessionKey) 

5955 except ValueError as ex: 

5956 warning("KerberosSSP: %s (bad KEY?)" % ex) 

5957 return Context, None, GSS_S_DEFECTIVE_TOKEN 

5958 return Context, None, GSS_S_COMPLETE # success 

5959 else: 

5960 raise ValueError("KerberosSSP: Unknown state %s" % repr(Context.state)) 

5961 

5962 def GSS_Passive( 

5963 self, 

5964 Context: CONTEXT, 

5965 input_token=None, 

5966 req_flags: Optional[GSS_S_FLAGS] = GSS_S_FLAGS.GSS_S_ALLOW_MISSING_BINDINGS, 

5967 ): 

5968 if Context is None: 

5969 Context = self.CONTEXT(True) 

5970 Context.passive = True 

5971 

5972 if Context.state == self.STATE.INIT or ( 

5973 # In DCE/RPC, there's an extra AP-REP sent from the client. 

5974 Context.state == self.STATE.SRV_SENT_APREP 

5975 and req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE 

5976 ): 

5977 Context, _, status = self.GSS_Accept_sec_context( 

5978 Context, 

5979 input_token=input_token, 

5980 req_flags=req_flags, 

5981 ) 

5982 if status in [GSS_S_CONTINUE_NEEDED, GSS_S_COMPLETE]: 

5983 Context.state = self.STATE.CLI_SENT_APREQ 

5984 else: 

5985 Context.state = self.STATE.FAILED 

5986 elif Context.state == self.STATE.CLI_SENT_APREQ: 

5987 Context, _, status = self.GSS_Init_sec_context( 

5988 Context, 

5989 input_token=input_token, 

5990 req_flags=req_flags, 

5991 ) 

5992 if status == GSS_S_COMPLETE: 

5993 if req_flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

5994 status = GSS_S_CONTINUE_NEEDED 

5995 Context.state = self.STATE.SRV_SENT_APREP 

5996 else: 

5997 Context.state == self.STATE.FAILED 

5998 else: 

5999 # Unknown state. Don't crash though. 

6000 status = GSS_S_FAILURE 

6001 

6002 return Context, status 

6003 

6004 def GSS_Passive_set_Direction(self, Context: CONTEXT, IsAcceptor=False): 

6005 if Context.IsAcceptor is not IsAcceptor: 

6006 return 

6007 # Swap everything 

6008 Context.SendSealKeyUsage, Context.RecvSealKeyUsage = ( 

6009 Context.RecvSealKeyUsage, 

6010 Context.SendSealKeyUsage, 

6011 ) 

6012 Context.SendSignKeyUsage, Context.RecvSignKeyUsage = ( 

6013 Context.RecvSignKeyUsage, 

6014 Context.SendSignKeyUsage, 

6015 ) 

6016 Context.IsAcceptor = not Context.IsAcceptor 

6017 

6018 def LegsAmount(self, Context: CONTEXT): 

6019 if Context.flags & GSS_C_FLAGS.GSS_C_DCE_STYLE: 

6020 return 4 

6021 else: 

6022 return 2 

6023 

6024 def MaximumSignatureLength(self, Context: CONTEXT): 

6025 if Context.flags & GSS_C_FLAGS.GSS_C_CONF_FLAG: 

6026 # TODO: support DES 

6027 if Context.KrbSessionKey.etype in [17, 18]: # AES 

6028 return 76 

6029 elif Context.KrbSessionKey.etype in [23, 24]: # RC4_HMAC 

6030 return 45 

6031 else: 

6032 raise NotImplementedError 

6033 else: 

6034 return 28