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

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

241 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 <gabriel[]potter[]fr> 

5 

6""" 

7Generic Security Services (GSS) API 

8 

9Implements parts of: 

10 

11 - GSSAPI: RFC4121 / RFC2743 

12 - GSSAPI C bindings: RFC2744 

13 - Channel Bindings for TLS: RFC5929 

14 

15This is implemented in the following SSPs: 

16 

17 - :class:`~scapy.layers.ntlm.NTLMSSP` 

18 - :class:`~scapy.layers.kerberos.KerberosSSP` 

19 - :class:`~scapy.layers.spnego.SPNEGOSSP` 

20 - :class:`~scapy.layers.msrpce.msnrpc.NetlogonSSP` 

21 

22.. note:: 

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

24 `GSSAPI <https://scapy.readthedocs.io/en/latest/layers/gssapi.html>`_ 

25""" 

26 

27import abc 

28 

29from dataclasses import dataclass 

30from enum import Enum, IntEnum, IntFlag 

31 

32from scapy.asn1.asn1 import ( 

33 ASN1_SEQUENCE, 

34 ASN1_Class_UNIVERSAL, 

35 ASN1_Codecs, 

36) 

37from scapy.asn1.ber import BERcodec_SEQUENCE 

38from scapy.asn1.mib import conf # loads conf.mib 

39from scapy.asn1fields import ( 

40 ASN1F_OID, 

41 ASN1F_PACKET, 

42 ASN1F_SEQUENCE, 

43) 

44from scapy.asn1packet import ASN1_Packet 

45from scapy.error import log_runtime 

46from scapy.fields import ( 

47 FieldLenField, 

48 LEIntEnumField, 

49 PacketField, 

50 StrLenField, 

51) 

52from scapy.packet import Packet 

53 

54# Type hints 

55from typing import ( 

56 Any, 

57 List, 

58 Optional, 

59 Tuple, 

60) 

61 

62# https://datatracker.ietf.org/doc/html/rfc1508#page-48 

63 

64 

65class ASN1_Class_GSSAPI(ASN1_Class_UNIVERSAL): 

66 name = "GSSAPI" 

67 APPLICATION = 0x60 

68 

69 

70class ASN1_GSSAPI_APPLICATION(ASN1_SEQUENCE): 

71 tag = ASN1_Class_GSSAPI.APPLICATION 

72 

73 

74class BERcodec_GSSAPI_APPLICATION(BERcodec_SEQUENCE): 

75 tag = ASN1_Class_GSSAPI.APPLICATION 

76 

77 

78class ASN1F_GSSAPI_APPLICATION(ASN1F_SEQUENCE): 

79 ASN1_tag = ASN1_Class_GSSAPI.APPLICATION 

80 

81 

82# GSS API Blob 

83# https://datatracker.ietf.org/doc/html/rfc4121 

84 

85# Filled by providers 

86_GSSAPI_OIDS = {} 

87_GSSAPI_SIGNATURE_OIDS = {} 

88 

89# section 4.1 

90 

91 

92class GSSAPI_BLOB(ASN1_Packet): 

93 ASN1_codec = ASN1_Codecs.BER 

94 ASN1_root = ASN1F_GSSAPI_APPLICATION( 

95 ASN1F_OID("MechType", "1.3.6.1.5.5.2"), 

96 ASN1F_PACKET( 

97 "innerToken", 

98 None, 

99 None, 

100 next_cls_cb=lambda pkt: _GSSAPI_OIDS.get(pkt.MechType.val, conf.raw_layer), 

101 ), 

102 ) 

103 

104 @classmethod 

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

106 if _pkt and len(_pkt) >= 1: 

107 if ord(_pkt[:1]) & 0xA0 >= 0xA0: 

108 from scapy.layers.spnego import SPNEGO_negToken 

109 

110 # XXX: sometimes the token is raw, we should look from 

111 # the session what to use here. For now: hardcode SPNEGO 

112 # (THIS IS A VERY STRONG ASSUMPTION) 

113 return SPNEGO_negToken 

114 if _pkt[:7] == b"NTLMSSP": 

115 from scapy.layers.ntlm import NTLM_Header 

116 

117 # XXX: if no mechTypes are provided during SPNEGO exchange, 

118 # Windows falls back to a plain NTLM_Header. 

119 return NTLM_Header.dispatch_hook(_pkt=_pkt, *args, **kargs) 

120 return cls 

121 

122 

123# Same but to store the signatures (e.g. DCE/RPC) 

124 

125 

126class GSSAPI_BLOB_SIGNATURE(ASN1_Packet): 

127 ASN1_codec = ASN1_Codecs.BER 

128 ASN1_root = ASN1F_GSSAPI_APPLICATION( 

129 ASN1F_OID("MechType", "1.3.6.1.5.5.2"), 

130 ASN1F_PACKET( 

131 "innerToken", 

132 None, 

133 None, 

134 next_cls_cb=lambda pkt: _GSSAPI_SIGNATURE_OIDS.get( 

135 pkt.MechType.val, conf.raw_layer 

136 ), # noqa: E501 

137 ), 

138 ) 

139 

140 @classmethod 

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

142 if _pkt and len(_pkt) >= 2: 

143 # Sometimes the token is raw. Detect that with educated 

144 # heuristics. 

145 if _pkt[:2] in [b"\x04\x04", b"\x05\x04"]: 

146 from scapy.layers.kerberos import KRB_InnerToken 

147 

148 return KRB_InnerToken 

149 elif len(_pkt) >= 4 and _pkt[:4] == b"\x01\x00\x00\x00": 

150 from scapy.layers.ntlm import NTLMSSP_MESSAGE_SIGNATURE 

151 

152 return NTLMSSP_MESSAGE_SIGNATURE 

153 return cls 

154 

155 

156class _GSSAPI_Field(PacketField): 

157 """ 

158 PacketField that contains a GSSAPI_BLOB_SIGNATURE, but one that can 

159 have a payload when not encrypted. 

160 """ 

161 

162 __slots__ = ["pay_cls"] 

163 

164 def __init__(self, name, pay_cls): 

165 self.pay_cls = pay_cls 

166 super().__init__( 

167 name, 

168 None, 

169 GSSAPI_BLOB_SIGNATURE, 

170 ) 

171 

172 def getfield(self, pkt, s): 

173 remain, val = super().getfield(pkt, s) 

174 if remain and val: 

175 val.payload = self.pay_cls(remain) 

176 return b"", val 

177 return remain, val 

178 

179 

180# RFC2744 Annex A, Null values 

181 

182GSS_C_QOP_DEFAULT = 0 

183GSS_C_NO_CHANNEL_BINDINGS = b"\x00" 

184 

185 

186# RFC2744 sect 3.9 - Status Values 

187 

188GSS_S_COMPLETE = 0 

189 

190# These errors are encoded into the 32-bit GSS status code as follows: 

191# MSB LSB 

192# |------------------------------------------------------------| 

193# | Calling Error | Routine Error | Supplementary Info | 

194# |------------------------------------------------------------| 

195# Bit 31 24 23 16 15 0 

196 

197GSS_C_CALLING_ERROR_OFFSET = 24 

198GSS_C_ROUTINE_ERROR_OFFSET = 16 

199GSS_C_SUPPLEMENTARY_OFFSET = 0 

200 

201# Calling errors: 

202 

203GSS_S_CALL_INACCESSIBLE_READ = 1 << GSS_C_CALLING_ERROR_OFFSET 

204GSS_S_CALL_INACCESSIBLE_WRITE = 2 << GSS_C_CALLING_ERROR_OFFSET 

205GSS_S_CALL_BAD_STRUCTURE = 3 << GSS_C_CALLING_ERROR_OFFSET 

206 

207# Routine errors: 

208 

209GSS_S_BAD_MECH = 1 << GSS_C_ROUTINE_ERROR_OFFSET 

210GSS_S_BAD_NAME = 2 << GSS_C_ROUTINE_ERROR_OFFSET 

211GSS_S_BAD_NAMETYPE = 3 << GSS_C_ROUTINE_ERROR_OFFSET 

212GSS_S_BAD_BINDINGS = 4 << GSS_C_ROUTINE_ERROR_OFFSET 

213GSS_S_BAD_STATUS = 5 << GSS_C_ROUTINE_ERROR_OFFSET 

214GSS_S_BAD_SIG = 6 << GSS_C_ROUTINE_ERROR_OFFSET 

215GSS_S_BAD_MIC = GSS_S_BAD_SIG 

216GSS_S_NO_CRED = 7 << GSS_C_ROUTINE_ERROR_OFFSET 

217GSS_S_NO_CONTEXT = 8 << GSS_C_ROUTINE_ERROR_OFFSET 

218GSS_S_DEFECTIVE_TOKEN = 9 << GSS_C_ROUTINE_ERROR_OFFSET 

219GSS_S_DEFECTIVE_CREDENTIAL = 10 << GSS_C_ROUTINE_ERROR_OFFSET 

220GSS_S_CREDENTIALS_EXPIRED = 11 << GSS_C_ROUTINE_ERROR_OFFSET 

221GSS_S_CONTEXT_EXPIRED = 12 << GSS_C_ROUTINE_ERROR_OFFSET 

222GSS_S_FAILURE = 13 << GSS_C_ROUTINE_ERROR_OFFSET 

223GSS_S_BAD_QOP = 14 << GSS_C_ROUTINE_ERROR_OFFSET 

224GSS_S_UNAUTHORIZED = 15 << GSS_C_ROUTINE_ERROR_OFFSET 

225GSS_S_UNAVAILABLE = 16 << GSS_C_ROUTINE_ERROR_OFFSET 

226GSS_S_DUPLICATE_ELEMENT = 17 << GSS_C_ROUTINE_ERROR_OFFSET 

227GSS_S_NAME_NOT_MN = 18 << GSS_C_ROUTINE_ERROR_OFFSET 

228 

229# Supplementary info bits: 

230 

231GSS_S_CONTINUE_NEEDED = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 0) 

232GSS_S_DUPLICATE_TOKEN = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1) 

233GSS_S_OLD_TOKEN = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2) 

234GSS_S_UNSEQ_TOKEN = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3) 

235GSS_S_GAP_TOKEN = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4) 

236 

237# Address families (RFC2744 sect 3.11) 

238 

239_GSS_ADDRTYPE = { 

240 0: "GSS_C_AF_UNSPEC", 

241 1: "GSS_C_AF_LOCAL", 

242 2: "GSS_C_AF_INET", 

243 3: "GSS_C_AF_IMPLINK", 

244 4: "GSS_C_AF_PUP", 

245 5: "GSS_C_AF_CHAOS", 

246 6: "GSS_C_AF_NS", 

247 7: "GSS_C_AF_NBS", 

248 8: "GSS_C_AF_ECMA", 

249 9: "GSS_C_AF_DATAKIT", 

250 10: "GSS_C_AF_CCITT", 

251 11: "GSS_C_AF_SNA", 

252 12: "GSS_C_AF_DECnet", 

253 13: "GSS_C_AF_DLI", 

254 14: "GSS_C_AF_LAT", 

255 15: "GSS_C_AF_HYLINK", 

256 16: "GSS_C_AF_APPLETALK", 

257 17: "GSS_C_AF_BSC", 

258 18: "GSS_C_AF_DSS", 

259 19: "GSS_C_AF_OSI", 

260 21: "GSS_C_AF_X25", 

261 255: "GSS_C_AF_NULLADDR", 

262} 

263 

264 

265# GSS Structures 

266 

267 

268class ChannelBindingType(Enum): 

269 """ 

270 Channel Binding Application Data types, per: 

271 RFC 5929 / RFC 9266 

272 """ 

273 

274 TLS_UNIQUE = "unique" 

275 TLS_SERVER_END_POINT = "tls-server-end-point" 

276 TLS_UNIQUE_FOR_TELNET = "tls-unique-for-telnet" 

277 TLS_EXPORTER = "tls-exporter" # RFC9266 

278 

279 

280class GssBufferDesc(Packet): 

281 name = "gss_buffer_desc" 

282 fields_desc = [ 

283 FieldLenField("length", None, length_of="value", fmt="<I"), 

284 StrLenField("value", "", length_from=lambda pkt: pkt.length), 

285 ] 

286 

287 def default_payload_class(self, payload): 

288 return conf.padding_layer 

289 

290 

291class GssChannelBindings(Packet): 

292 name = "gss_channel_bindings_struct" 

293 fields_desc = [ 

294 LEIntEnumField("initiator_addrtype", 0, _GSS_ADDRTYPE), 

295 PacketField("initiator_address", GssBufferDesc(), GssBufferDesc), 

296 LEIntEnumField("acceptor_addrtype", 0, _GSS_ADDRTYPE), 

297 PacketField("acceptor_address", GssBufferDesc(), GssBufferDesc), 

298 PacketField("application_data", None, GssBufferDesc), 

299 ] 

300 

301 def digestMD5(self): 

302 """ 

303 Calculate a MD5 hash of the channel binding 

304 """ 

305 from scapy.layers.tls.crypto.hash import Hash_MD5 

306 

307 return Hash_MD5().digest(bytes(self)) 

308 

309 @classmethod 

310 def fromssl( 

311 cls, 

312 token_type: ChannelBindingType, 

313 sslsock=None, 

314 certfile=None, 

315 ) -> "GssChannelBindings": 

316 """ 

317 Build a GssChannelBindings struct from a socket 

318 

319 :param token_type: the type from ChannelBindingType, per RFC5929 

320 :param sslsock: take the certificate from the the socket.socket object 

321 :param certfile: take the certificate from a file 

322 """ 

323 from scapy.layers.tls.cert import Cert 

324 from cryptography.hazmat.primitives import hashes 

325 

326 if token_type == ChannelBindingType.TLS_SERVER_END_POINT: 

327 # RFC5929 sect 4 

328 try: 

329 # Parse certificate 

330 if certfile is not None: 

331 cert = Cert(certfile) 

332 else: 

333 cert = Cert(sslsock.getpeercert(binary_form=True)) 

334 except Exception: 

335 # We failed to parse the certificate. 

336 log_runtime.warning("Failed to parse the SSL Certificate. CBT not used") 

337 return GSS_C_NO_CHANNEL_BINDINGS 

338 try: 

339 h = cert.getSignatureHash() 

340 except Exception: 

341 # We failed to get the signature algorithm. 

342 log_runtime.warning( 

343 "Failed to get the Certificate signature algorithm. CBT not used" 

344 ) 

345 return GSS_C_NO_CHANNEL_BINDINGS 

346 # RFC5929 sect 4.1 

347 if h == hashes.MD5 or h == hashes.SHA1: 

348 h = hashes.SHA256 

349 # Get bytes of first certificate if there are multiple 

350 c = cert.x509Cert.copy() 

351 c.remove_payload() 

352 cdata = bytes(c) 

353 # Calc hash of certificate 

354 digest = hashes.Hash(h) 

355 digest.update(cdata) 

356 cbdata = digest.finalize() 

357 elif token_type == ChannelBindingType.TLS_UNIQUE: 

358 # RFC5929 sect 3 

359 cbdata = sslsock.get_channel_binding(cb_type="tls-unique") 

360 else: 

361 raise NotImplementedError 

362 # RFC5056 sect 2.1 

363 # "channel bindings MUST start with the channel binding unique prefix followed 

364 # by a colon (ASCII 0x3A)." 

365 return GssChannelBindings( 

366 application_data=GssBufferDesc( 

367 value=token_type.value.encode() + b":" + cbdata 

368 ) 

369 ) 

370 

371 

372# --- The base GSSAPI SSP base class 

373 

374 

375class GSS_C_FLAGS(IntFlag): 

376 """ 

377 Authenticator Flags per RFC2744 req_flags 

378 """ 

379 

380 GSS_C_DELEG_FLAG = 0x01 

381 GSS_C_MUTUAL_FLAG = 0x02 

382 GSS_C_REPLAY_FLAG = 0x04 

383 GSS_C_SEQUENCE_FLAG = 0x08 

384 GSS_C_CONF_FLAG = 0x10 # confidentiality 

385 GSS_C_INTEG_FLAG = 0x20 # integrity 

386 # RFC4757 

387 GSS_C_DCE_STYLE = 0x1000 

388 GSS_C_IDENTIFY_FLAG = 0x2000 

389 GSS_C_EXTENDED_ERROR_FLAG = 0x4000 

390 

391 

392class GSS_S_FLAGS(IntFlag): 

393 """ 

394 Equivalent to Microsoft's ASC_REQ* Flags in AcceptSecurityContext 

395 """ 

396 

397 GSS_S_ALLOW_MISSING_BINDINGS = 0x10000000 

398 

399 

400class SSP: 

401 """ 

402 The general SSP class 

403 """ 

404 

405 auth_type = 0x00 

406 

407 def __init__(self, **kwargs): 

408 if kwargs: 

409 raise ValueError("Unknown SSP parameters: " + ",".join(list(kwargs))) 

410 

411 def __repr__(self): 

412 return "<%s>" % self.__class__.__name__ 

413 

414 class CONTEXT: 

415 """ 

416 A Security context i.e. the 'state' of the secure negotiation 

417 """ 

418 

419 __slots__ = ["state", "_flags", "passive"] 

420 

421 def __init__(self, req_flags: Optional["GSS_C_FLAGS | GSS_S_FLAGS"] = None): 

422 if req_flags is None: 

423 # Default 

424 req_flags = ( 

425 GSS_C_FLAGS.GSS_C_EXTENDED_ERROR_FLAG 

426 | GSS_C_FLAGS.GSS_C_MUTUAL_FLAG 

427 ) 

428 self.flags = req_flags 

429 self.passive = False 

430 

431 def clifailure(self): 

432 # This allows to reset the client context without discarding it. 

433 pass 

434 

435 # 'flags' is the most important attribute. Use a setter to sanitize it. 

436 

437 @property 

438 def flags(self): 

439 return self._flags 

440 

441 @flags.setter 

442 def flags(self, x): 

443 self._flags = GSS_C_FLAGS(int(x)) 

444 

445 def __repr__(self): 

446 return "[Default SSP]" 

447 

448 class STATE(IntEnum): 

449 """ 

450 An Enum that contains the states of an SSP 

451 """ 

452 

453 @abc.abstractmethod 

454 def GSS_Init_sec_context( 

455 self, 

456 Context: CONTEXT, 

457 token=None, 

458 req_flags: Optional[GSS_C_FLAGS] = None, 

459 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

460 ): 

461 """ 

462 GSS_Init_sec_context: client-side call for the SSP 

463 """ 

464 raise NotImplementedError 

465 

466 @abc.abstractmethod 

467 def GSS_Accept_sec_context( 

468 self, 

469 Context: CONTEXT, 

470 token=None, 

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

472 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

473 ): 

474 """ 

475 GSS_Accept_sec_context: server-side call for the SSP 

476 """ 

477 raise NotImplementedError 

478 

479 # Passive 

480 

481 @abc.abstractmethod 

482 def GSS_Passive(self, Context: CONTEXT, token=None): 

483 """ 

484 GSS_Passive: client/server call for the SSP in passive mode 

485 """ 

486 raise NotImplementedError 

487 

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

489 """ 

490 GSS_Passive_set_Direction: used to swap the direction in passive mode 

491 """ 

492 pass 

493 

494 # MS additions (*Ex functions) 

495 

496 @dataclass 

497 class WRAP_MSG: 

498 conf_req_flag: bool 

499 sign: bool 

500 data: bytes 

501 

502 @abc.abstractmethod 

503 def GSS_WrapEx( 

504 self, 

505 Context: CONTEXT, 

506 msgs: List[WRAP_MSG], 

507 qop_req: int = GSS_C_QOP_DEFAULT, 

508 ) -> Tuple[List[WRAP_MSG], Any]: 

509 """ 

510 GSS_WrapEx 

511 

512 :param Context: the SSP context 

513 :param qop_req: int (0 specifies default QOP) 

514 :param msgs: list of WRAP_MSG 

515 

516 :returns: (data, signature) 

517 """ 

518 raise NotImplementedError 

519 

520 @abc.abstractmethod 

521 def GSS_UnwrapEx( 

522 self, Context: CONTEXT, msgs: List[WRAP_MSG], signature 

523 ) -> List[WRAP_MSG]: 

524 """ 

525 :param Context: the SSP context 

526 :param msgs: list of WRAP_MSG 

527 :param signature: the signature 

528 

529 :raises ValueError: if MIC failure. 

530 :returns: data 

531 """ 

532 raise NotImplementedError 

533 

534 @dataclass 

535 class MIC_MSG: 

536 sign: bool 

537 data: bytes 

538 

539 @abc.abstractmethod 

540 def GSS_GetMICEx( 

541 self, 

542 Context: CONTEXT, 

543 msgs: List[MIC_MSG], 

544 qop_req: int = GSS_C_QOP_DEFAULT, 

545 ) -> Any: 

546 """ 

547 GSS_GetMICEx 

548 

549 :param Context: the SSP context 

550 :param qop_req: int (0 specifies default QOP) 

551 :param msgs: list of VERIF_MSG 

552 

553 :returns: signature 

554 """ 

555 raise NotImplementedError 

556 

557 @abc.abstractmethod 

558 def GSS_VerifyMICEx( 

559 self, 

560 Context: CONTEXT, 

561 msgs: List[MIC_MSG], 

562 signature, 

563 ) -> None: 

564 """ 

565 :param Context: the SSP context 

566 :param msgs: list of VERIF_MSG 

567 :param signature: the signature 

568 

569 :raises ValueError: if MIC failure. 

570 """ 

571 raise NotImplementedError 

572 

573 @abc.abstractmethod 

574 def MaximumSignatureLength(self, Context: CONTEXT): 

575 """ 

576 Returns the Maximum Signature length. 

577 

578 This will be used in auth_len in DceRpc5, and is necessary for 

579 PFC_SUPPORT_HEADER_SIGN to work properly. 

580 """ 

581 raise NotImplementedError 

582 

583 # RFC 2743 

584 

585 # sect 2.3.1 

586 

587 def GSS_GetMIC( 

588 self, 

589 Context: CONTEXT, 

590 message: bytes, 

591 qop_req: int = GSS_C_QOP_DEFAULT, 

592 ): 

593 return self.GSS_GetMICEx( 

594 Context, 

595 [ 

596 self.MIC_MSG( 

597 sign=True, 

598 data=message, 

599 ) 

600 ], 

601 qop_req=qop_req, 

602 ) 

603 

604 # sect 2.3.2 

605 

606 def GSS_VerifyMIC( 

607 self, 

608 Context: CONTEXT, 

609 message: bytes, 

610 signature, 

611 ): 

612 self.GSS_VerifyMICEx( 

613 Context, 

614 [ 

615 self.MIC_MSG( 

616 sign=True, 

617 data=message, 

618 ) 

619 ], 

620 signature, 

621 ) 

622 

623 # sect 2.3.3 

624 

625 def GSS_Wrap( 

626 self, 

627 Context: CONTEXT, 

628 input_message: bytes, 

629 conf_req_flag: bool, 

630 qop_req: int = GSS_C_QOP_DEFAULT, 

631 ): 

632 _msgs, signature = self.GSS_WrapEx( 

633 Context, 

634 [ 

635 self.WRAP_MSG( 

636 conf_req_flag=conf_req_flag, 

637 sign=True, 

638 data=input_message, 

639 ) 

640 ], 

641 qop_req=qop_req, 

642 ) 

643 if _msgs[0].data: 

644 signature /= _msgs[0].data 

645 return signature 

646 

647 # sect 2.3.4 

648 

649 def GSS_Unwrap(self, Context: CONTEXT, signature): 

650 data = b"" 

651 if signature.payload: 

652 # signature has a payload that is the data. Let's get that payload 

653 # in its original form, and use it for verifying the checksum. 

654 if signature.payload.original: 

655 data = signature.payload.original 

656 else: 

657 data = bytes(signature.payload) 

658 signature = signature.copy() 

659 signature.remove_payload() 

660 return self.GSS_UnwrapEx( 

661 Context, 

662 [ 

663 self.WRAP_MSG( 

664 conf_req_flag=True, 

665 sign=True, 

666 data=data, 

667 ) 

668 ], 

669 signature, 

670 )[0].data 

671 

672 # MISC 

673 

674 def NegTokenInit2(self): 

675 """ 

676 Server-Initiation 

677 See [MS-SPNG] sect 3.2.5.2 

678 """ 

679 return None, None 

680 

681 def canMechListMIC(self, Context: CONTEXT): 

682 """ 

683 Returns whether or not mechListMIC can be computed 

684 """ 

685 return False 

686 

687 def getMechListMIC(self, Context, input): 

688 """ 

689 Compute mechListMIC 

690 """ 

691 return bytes(self.GSS_GetMIC(Context, input)) 

692 

693 def verifyMechListMIC(self, Context, otherMIC, input): 

694 """ 

695 Verify mechListMIC 

696 """ 

697 return self.GSS_VerifyMIC(Context, input, otherMIC) 

698 

699 def LegsAmount(self, Context: CONTEXT): 

700 """ 

701 Returns the amount of 'legs' (how MS calls it) of the SSP. 

702 

703 i.e. 2 for Kerberos, 3 for NTLM and Netlogon 

704 """ 

705 return 2