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 target_name: Optional[str] = None, 

459 req_flags: Optional[GSS_C_FLAGS] = None, 

460 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

461 ): 

462 """ 

463 GSS_Init_sec_context: client-side call for the SSP 

464 """ 

465 raise NotImplementedError 

466 

467 @abc.abstractmethod 

468 def GSS_Accept_sec_context( 

469 self, 

470 Context: CONTEXT, 

471 token=None, 

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

473 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

474 ): 

475 """ 

476 GSS_Accept_sec_context: server-side call for the SSP 

477 """ 

478 raise NotImplementedError 

479 

480 # Passive 

481 

482 @abc.abstractmethod 

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

484 """ 

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

486 """ 

487 raise NotImplementedError 

488 

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

490 """ 

491 GSS_Passive_set_Direction: used to swap the direction in passive mode 

492 """ 

493 pass 

494 

495 # MS additions (*Ex functions) 

496 

497 @dataclass 

498 class WRAP_MSG: 

499 conf_req_flag: bool 

500 sign: bool 

501 data: bytes 

502 

503 @abc.abstractmethod 

504 def GSS_WrapEx( 

505 self, 

506 Context: CONTEXT, 

507 msgs: List[WRAP_MSG], 

508 qop_req: int = GSS_C_QOP_DEFAULT, 

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

510 """ 

511 GSS_WrapEx 

512 

513 :param Context: the SSP context 

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

515 :param msgs: list of WRAP_MSG 

516 

517 :returns: (data, signature) 

518 """ 

519 raise NotImplementedError 

520 

521 @abc.abstractmethod 

522 def GSS_UnwrapEx( 

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

524 ) -> List[WRAP_MSG]: 

525 """ 

526 :param Context: the SSP context 

527 :param msgs: list of WRAP_MSG 

528 :param signature: the signature 

529 

530 :raises ValueError: if MIC failure. 

531 :returns: data 

532 """ 

533 raise NotImplementedError 

534 

535 @dataclass 

536 class MIC_MSG: 

537 sign: bool 

538 data: bytes 

539 

540 @abc.abstractmethod 

541 def GSS_GetMICEx( 

542 self, 

543 Context: CONTEXT, 

544 msgs: List[MIC_MSG], 

545 qop_req: int = GSS_C_QOP_DEFAULT, 

546 ) -> Any: 

547 """ 

548 GSS_GetMICEx 

549 

550 :param Context: the SSP context 

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

552 :param msgs: list of VERIF_MSG 

553 

554 :returns: signature 

555 """ 

556 raise NotImplementedError 

557 

558 @abc.abstractmethod 

559 def GSS_VerifyMICEx( 

560 self, 

561 Context: CONTEXT, 

562 msgs: List[MIC_MSG], 

563 signature, 

564 ) -> None: 

565 """ 

566 :param Context: the SSP context 

567 :param msgs: list of VERIF_MSG 

568 :param signature: the signature 

569 

570 :raises ValueError: if MIC failure. 

571 """ 

572 raise NotImplementedError 

573 

574 @abc.abstractmethod 

575 def MaximumSignatureLength(self, Context: CONTEXT): 

576 """ 

577 Returns the Maximum Signature length. 

578 

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

580 PFC_SUPPORT_HEADER_SIGN to work properly. 

581 """ 

582 raise NotImplementedError 

583 

584 # RFC 2743 

585 

586 # sect 2.3.1 

587 

588 def GSS_GetMIC( 

589 self, 

590 Context: CONTEXT, 

591 message: bytes, 

592 qop_req: int = GSS_C_QOP_DEFAULT, 

593 ): 

594 return self.GSS_GetMICEx( 

595 Context, 

596 [ 

597 self.MIC_MSG( 

598 sign=True, 

599 data=message, 

600 ) 

601 ], 

602 qop_req=qop_req, 

603 ) 

604 

605 # sect 2.3.2 

606 

607 def GSS_VerifyMIC( 

608 self, 

609 Context: CONTEXT, 

610 message: bytes, 

611 signature, 

612 ): 

613 self.GSS_VerifyMICEx( 

614 Context, 

615 [ 

616 self.MIC_MSG( 

617 sign=True, 

618 data=message, 

619 ) 

620 ], 

621 signature, 

622 ) 

623 

624 # sect 2.3.3 

625 

626 def GSS_Wrap( 

627 self, 

628 Context: CONTEXT, 

629 input_message: bytes, 

630 conf_req_flag: bool, 

631 qop_req: int = GSS_C_QOP_DEFAULT, 

632 ): 

633 _msgs, signature = self.GSS_WrapEx( 

634 Context, 

635 [ 

636 self.WRAP_MSG( 

637 conf_req_flag=conf_req_flag, 

638 sign=True, 

639 data=input_message, 

640 ) 

641 ], 

642 qop_req=qop_req, 

643 ) 

644 if _msgs[0].data: 

645 signature /= _msgs[0].data 

646 return signature 

647 

648 # sect 2.3.4 

649 

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

651 data = b"" 

652 if signature.payload: 

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

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

655 if signature.payload.original: 

656 data = signature.payload.original 

657 else: 

658 data = bytes(signature.payload) 

659 signature = signature.copy() 

660 signature.remove_payload() 

661 return self.GSS_UnwrapEx( 

662 Context, 

663 [ 

664 self.WRAP_MSG( 

665 conf_req_flag=True, 

666 sign=True, 

667 data=data, 

668 ) 

669 ], 

670 signature, 

671 )[0].data 

672 

673 # MISC 

674 

675 def NegTokenInit2(self): 

676 """ 

677 Server-Initiation 

678 See [MS-SPNG] sect 3.2.5.2 

679 """ 

680 return None, None 

681 

682 def canMechListMIC(self, Context: CONTEXT): 

683 """ 

684 Returns whether or not mechListMIC can be computed 

685 """ 

686 return False 

687 

688 def getMechListMIC(self, Context, input): 

689 """ 

690 Compute mechListMIC 

691 """ 

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

693 

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

695 """ 

696 Verify mechListMIC 

697 """ 

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

699 

700 def LegsAmount(self, Context: CONTEXT): 

701 """ 

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

703 

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

705 """ 

706 return 2