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

247 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, BER_id_dec 

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 _pkt[0] & 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 elif _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 elif BER_id_dec(_pkt)[0] & 0x7F > 0x60: 

121 from scapy.layers.kerberos import Kerberos 

122 

123 # XXX: Heuristic to detect raw Kerberos packets, when Windows 

124 # fallsback or when the parent data hasn't got any mechtype specified. 

125 return Kerberos 

126 return cls 

127 

128 

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

130 

131 

132class GSSAPI_BLOB_SIGNATURE(ASN1_Packet): 

133 ASN1_codec = ASN1_Codecs.BER 

134 ASN1_root = ASN1F_GSSAPI_APPLICATION( 

135 ASN1F_OID("MechType", "1.3.6.1.5.5.2"), 

136 ASN1F_PACKET( 

137 "innerToken", 

138 None, 

139 None, 

140 next_cls_cb=lambda pkt: _GSSAPI_SIGNATURE_OIDS.get( 

141 pkt.MechType.val, conf.raw_layer 

142 ), # noqa: E501 

143 ), 

144 ) 

145 

146 @classmethod 

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

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

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

150 # heuristics. 

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

152 from scapy.layers.kerberos import KRB_InnerToken 

153 

154 return KRB_InnerToken 

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

156 from scapy.layers.ntlm import NTLMSSP_MESSAGE_SIGNATURE 

157 

158 return NTLMSSP_MESSAGE_SIGNATURE 

159 return cls 

160 

161 

162class _GSSAPI_Field(PacketField): 

163 """ 

164 PacketField that contains a GSSAPI_BLOB_SIGNATURE, but one that can 

165 have a payload when not encrypted. 

166 """ 

167 

168 __slots__ = ["pay_cls"] 

169 

170 def __init__(self, name, pay_cls): 

171 self.pay_cls = pay_cls 

172 super().__init__( 

173 name, 

174 None, 

175 GSSAPI_BLOB_SIGNATURE, 

176 ) 

177 

178 def getfield(self, pkt, s): 

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

180 if remain and val: 

181 val.payload = self.pay_cls(remain) 

182 return b"", val 

183 return remain, val 

184 

185 

186# RFC2744 Annex A, Null values 

187 

188GSS_C_QOP_DEFAULT = 0 

189GSS_C_NO_CHANNEL_BINDINGS = b"\x00" 

190 

191 

192# RFC2744 sect 3.9 - Status Values 

193 

194GSS_S_COMPLETE = 0 

195 

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

197# MSB LSB 

198# |------------------------------------------------------------| 

199# | Calling Error | Routine Error | Supplementary Info | 

200# |------------------------------------------------------------| 

201# Bit 31 24 23 16 15 0 

202 

203GSS_C_CALLING_ERROR_OFFSET = 24 

204GSS_C_ROUTINE_ERROR_OFFSET = 16 

205GSS_C_SUPPLEMENTARY_OFFSET = 0 

206 

207# Calling errors: 

208 

209GSS_S_CALL_INACCESSIBLE_READ = 1 << GSS_C_CALLING_ERROR_OFFSET 

210GSS_S_CALL_INACCESSIBLE_WRITE = 2 << GSS_C_CALLING_ERROR_OFFSET 

211GSS_S_CALL_BAD_STRUCTURE = 3 << GSS_C_CALLING_ERROR_OFFSET 

212 

213# Routine errors: 

214 

215GSS_S_BAD_MECH = 1 << GSS_C_ROUTINE_ERROR_OFFSET 

216GSS_S_BAD_NAME = 2 << GSS_C_ROUTINE_ERROR_OFFSET 

217GSS_S_BAD_NAMETYPE = 3 << GSS_C_ROUTINE_ERROR_OFFSET 

218GSS_S_BAD_BINDINGS = 4 << GSS_C_ROUTINE_ERROR_OFFSET 

219GSS_S_BAD_STATUS = 5 << GSS_C_ROUTINE_ERROR_OFFSET 

220GSS_S_BAD_SIG = 6 << GSS_C_ROUTINE_ERROR_OFFSET 

221GSS_S_BAD_MIC = GSS_S_BAD_SIG 

222GSS_S_NO_CRED = 7 << GSS_C_ROUTINE_ERROR_OFFSET 

223GSS_S_NO_CONTEXT = 8 << GSS_C_ROUTINE_ERROR_OFFSET 

224GSS_S_DEFECTIVE_TOKEN = 9 << GSS_C_ROUTINE_ERROR_OFFSET 

225GSS_S_DEFECTIVE_CREDENTIAL = 10 << GSS_C_ROUTINE_ERROR_OFFSET 

226GSS_S_CREDENTIALS_EXPIRED = 11 << GSS_C_ROUTINE_ERROR_OFFSET 

227GSS_S_CONTEXT_EXPIRED = 12 << GSS_C_ROUTINE_ERROR_OFFSET 

228GSS_S_FAILURE = 13 << GSS_C_ROUTINE_ERROR_OFFSET 

229GSS_S_BAD_QOP = 14 << GSS_C_ROUTINE_ERROR_OFFSET 

230GSS_S_UNAUTHORIZED = 15 << GSS_C_ROUTINE_ERROR_OFFSET 

231GSS_S_UNAVAILABLE = 16 << GSS_C_ROUTINE_ERROR_OFFSET 

232GSS_S_DUPLICATE_ELEMENT = 17 << GSS_C_ROUTINE_ERROR_OFFSET 

233GSS_S_NAME_NOT_MN = 18 << GSS_C_ROUTINE_ERROR_OFFSET 

234 

235# Supplementary info bits: 

236 

237GSS_S_CONTINUE_NEEDED = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 0) 

238GSS_S_DUPLICATE_TOKEN = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1) 

239GSS_S_OLD_TOKEN = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2) 

240GSS_S_UNSEQ_TOKEN = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3) 

241GSS_S_GAP_TOKEN = 1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4) 

242 

243# Address families (RFC2744 sect 3.11) 

244 

245_GSS_ADDRTYPE = { 

246 0: "GSS_C_AF_UNSPEC", 

247 1: "GSS_C_AF_LOCAL", 

248 2: "GSS_C_AF_INET", 

249 3: "GSS_C_AF_IMPLINK", 

250 4: "GSS_C_AF_PUP", 

251 5: "GSS_C_AF_CHAOS", 

252 6: "GSS_C_AF_NS", 

253 7: "GSS_C_AF_NBS", 

254 8: "GSS_C_AF_ECMA", 

255 9: "GSS_C_AF_DATAKIT", 

256 10: "GSS_C_AF_CCITT", 

257 11: "GSS_C_AF_SNA", 

258 12: "GSS_C_AF_DECnet", 

259 13: "GSS_C_AF_DLI", 

260 14: "GSS_C_AF_LAT", 

261 15: "GSS_C_AF_HYLINK", 

262 16: "GSS_C_AF_APPLETALK", 

263 17: "GSS_C_AF_BSC", 

264 18: "GSS_C_AF_DSS", 

265 19: "GSS_C_AF_OSI", 

266 21: "GSS_C_AF_X25", 

267 255: "GSS_C_AF_NULLADDR", 

268} 

269 

270 

271# GSS Structures 

272 

273 

274class ChannelBindingType(Enum): 

275 """ 

276 Channel Binding Application Data types, per: 

277 RFC 5929 / RFC 9266 

278 """ 

279 

280 TLS_UNIQUE = "unique" 

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

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

283 TLS_EXPORTER = "tls-exporter" # RFC9266 

284 

285 

286class GssBufferDesc(Packet): 

287 name = "gss_buffer_desc" 

288 fields_desc = [ 

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

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

291 ] 

292 

293 def default_payload_class(self, payload): 

294 return conf.padding_layer 

295 

296 

297class GssChannelBindings(Packet): 

298 name = "gss_channel_bindings_struct" 

299 fields_desc = [ 

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

301 PacketField("initiator_address", GssBufferDesc(), GssBufferDesc), 

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

303 PacketField("acceptor_address", GssBufferDesc(), GssBufferDesc), 

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

305 ] 

306 

307 def digestMD5(self): 

308 """ 

309 Calculate a MD5 hash of the channel binding 

310 """ 

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

312 

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

314 

315 @classmethod 

316 def fromssl( 

317 cls, 

318 token_type: ChannelBindingType, 

319 sslsock=None, 

320 certfile=None, 

321 ) -> "GssChannelBindings": 

322 """ 

323 Build a GssChannelBindings struct from a socket 

324 

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

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

327 :param certfile: take the certificate from a file 

328 """ 

329 from scapy.layers.tls.cert import Cert 

330 from cryptography.hazmat.primitives import hashes 

331 

332 if token_type == ChannelBindingType.TLS_SERVER_END_POINT: 

333 # RFC5929 sect 4 

334 try: 

335 # Parse certificate 

336 if certfile is not None: 

337 cert = Cert(certfile) 

338 else: 

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

340 except Exception: 

341 # We failed to parse the certificate. 

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

343 return GSS_C_NO_CHANNEL_BINDINGS 

344 try: 

345 h = cert.getSignatureHash() 

346 except Exception: 

347 # We failed to get the signature algorithm. 

348 log_runtime.warning( 

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

350 ) 

351 return GSS_C_NO_CHANNEL_BINDINGS 

352 # RFC5929 sect 4.1 

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

354 h = hashes.SHA256 

355 # Get bytes of first certificate if there are multiple 

356 c = cert.x509Cert.copy() 

357 c.remove_payload() 

358 cdata = bytes(c) 

359 # Calc hash of certificate 

360 digest = hashes.Hash(h) 

361 digest.update(cdata) 

362 cbdata = digest.finalize() 

363 elif token_type == ChannelBindingType.TLS_UNIQUE: 

364 # RFC5929 sect 3 

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

366 else: 

367 raise NotImplementedError 

368 # RFC5056 sect 2.1 

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

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

371 return GssChannelBindings( 

372 application_data=GssBufferDesc( 

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

374 ) 

375 ) 

376 

377 

378# --- The base GSSAPI SSP base class 

379 

380 

381class GSS_C_FLAGS(IntFlag): 

382 """ 

383 Authenticator Flags per RFC2744 req_flags 

384 """ 

385 

386 GSS_C_DELEG_FLAG = 0x01 

387 GSS_C_MUTUAL_FLAG = 0x02 

388 GSS_C_REPLAY_FLAG = 0x04 

389 GSS_C_SEQUENCE_FLAG = 0x08 

390 GSS_C_CONF_FLAG = 0x10 # confidentiality 

391 GSS_C_INTEG_FLAG = 0x20 # integrity 

392 # RFC4757 

393 GSS_C_DCE_STYLE = 0x1000 

394 GSS_C_IDENTIFY_FLAG = 0x2000 

395 GSS_C_EXTENDED_ERROR_FLAG = 0x4000 

396 

397 

398class GSS_S_FLAGS(IntFlag): 

399 """ 

400 Equivalent to Microsoft's ASC_REQ* Flags in AcceptSecurityContext 

401 """ 

402 

403 GSS_S_ALLOW_MISSING_BINDINGS = 0x10000000 

404 

405 

406class SSP: 

407 """ 

408 The general SSP class 

409 """ 

410 

411 auth_type = 0x00 

412 

413 def __init__(self, **kwargs): 

414 if kwargs: 

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

416 

417 def __repr__(self): 

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

419 

420 class CONTEXT: 

421 """ 

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

423 """ 

424 

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

426 

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

428 if req_flags is None: 

429 # Default 

430 req_flags = ( 

431 GSS_C_FLAGS.GSS_C_EXTENDED_ERROR_FLAG 

432 | GSS_C_FLAGS.GSS_C_MUTUAL_FLAG 

433 ) 

434 self.flags = req_flags 

435 self.passive = False 

436 

437 def clifailure(self): 

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

439 pass 

440 

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

442 

443 @property 

444 def flags(self): 

445 return self._flags 

446 

447 @flags.setter 

448 def flags(self, x): 

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

450 

451 def __repr__(self): 

452 return "[Default SSP]" 

453 

454 class STATE(IntEnum): 

455 """ 

456 An Enum that contains the states of an SSP 

457 """ 

458 

459 @abc.abstractmethod 

460 def GSS_Init_sec_context( 

461 self, 

462 Context: CONTEXT, 

463 input_token=None, 

464 target_name: Optional[str] = None, 

465 req_flags: Optional[GSS_C_FLAGS] = None, 

466 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

467 ): 

468 """ 

469 GSS_Init_sec_context: client-side call for the SSP 

470 """ 

471 raise NotImplementedError 

472 

473 @abc.abstractmethod 

474 def GSS_Accept_sec_context( 

475 self, 

476 Context: CONTEXT, 

477 input_token=None, 

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

479 chan_bindings: GssChannelBindings = GSS_C_NO_CHANNEL_BINDINGS, 

480 ): 

481 """ 

482 GSS_Accept_sec_context: server-side call for the SSP 

483 """ 

484 raise NotImplementedError 

485 

486 @abc.abstractmethod 

487 def GSS_Inquire_names_for_mech(self) -> List[str]: 

488 """ 

489 Get the available OIDs for this mech, in order of preference. 

490 """ 

491 raise NotImplementedError 

492 

493 # Passive 

494 

495 @abc.abstractmethod 

496 def GSS_Passive( 

497 self, 

498 Context: CONTEXT, 

499 input_token=None, 

500 ): 

501 """ 

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

503 """ 

504 raise NotImplementedError 

505 

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

507 """ 

508 GSS_Passive_set_Direction: used to swap the direction in passive mode 

509 """ 

510 pass 

511 

512 # MS additions (*Ex functions) 

513 

514 @dataclass 

515 class WRAP_MSG: 

516 conf_req_flag: bool 

517 sign: bool 

518 data: bytes 

519 

520 @abc.abstractmethod 

521 def GSS_WrapEx( 

522 self, 

523 Context: CONTEXT, 

524 msgs: List[WRAP_MSG], 

525 qop_req: int = GSS_C_QOP_DEFAULT, 

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

527 """ 

528 GSS_WrapEx 

529 

530 :param Context: the SSP context 

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

532 :param msgs: list of WRAP_MSG 

533 

534 :returns: (data, signature) 

535 """ 

536 raise NotImplementedError 

537 

538 @abc.abstractmethod 

539 def GSS_UnwrapEx( 

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

541 ) -> List[WRAP_MSG]: 

542 """ 

543 :param Context: the SSP context 

544 :param msgs: list of WRAP_MSG 

545 :param signature: the signature 

546 

547 :raises ValueError: if MIC failure. 

548 :returns: data 

549 """ 

550 raise NotImplementedError 

551 

552 @dataclass 

553 class MIC_MSG: 

554 sign: bool 

555 data: bytes 

556 

557 @abc.abstractmethod 

558 def GSS_GetMICEx( 

559 self, 

560 Context: CONTEXT, 

561 msgs: List[MIC_MSG], 

562 qop_req: int = GSS_C_QOP_DEFAULT, 

563 ) -> Any: 

564 """ 

565 GSS_GetMICEx 

566 

567 :param Context: the SSP context 

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

569 :param msgs: list of VERIF_MSG 

570 

571 :returns: signature 

572 """ 

573 raise NotImplementedError 

574 

575 @abc.abstractmethod 

576 def GSS_VerifyMICEx( 

577 self, 

578 Context: CONTEXT, 

579 msgs: List[MIC_MSG], 

580 signature, 

581 ) -> None: 

582 """ 

583 :param Context: the SSP context 

584 :param msgs: list of VERIF_MSG 

585 :param signature: the signature 

586 

587 :raises ValueError: if MIC failure. 

588 """ 

589 raise NotImplementedError 

590 

591 @abc.abstractmethod 

592 def MaximumSignatureLength(self, Context: CONTEXT): 

593 """ 

594 Returns the Maximum Signature length. 

595 

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

597 PFC_SUPPORT_HEADER_SIGN to work properly. 

598 """ 

599 raise NotImplementedError 

600 

601 # RFC 2743 

602 

603 # sect 2.3.1 

604 

605 def GSS_GetMIC( 

606 self, 

607 Context: CONTEXT, 

608 message: bytes, 

609 qop_req: int = GSS_C_QOP_DEFAULT, 

610 ): 

611 """ 

612 See GSS_GetMICEx 

613 """ 

614 return self.GSS_GetMICEx( 

615 Context, 

616 [ 

617 self.MIC_MSG( 

618 sign=True, 

619 data=message, 

620 ) 

621 ], 

622 qop_req=qop_req, 

623 ) 

624 

625 # sect 2.3.2 

626 

627 def GSS_VerifyMIC( 

628 self, 

629 Context: CONTEXT, 

630 message: bytes, 

631 signature, 

632 ) -> None: 

633 """ 

634 See GSS_VerifyMICEx 

635 """ 

636 self.GSS_VerifyMICEx( 

637 Context, 

638 [ 

639 self.MIC_MSG( 

640 sign=True, 

641 data=message, 

642 ) 

643 ], 

644 signature, 

645 ) 

646 

647 # sect 2.3.3 

648 

649 def GSS_Wrap( 

650 self, 

651 Context: CONTEXT, 

652 input_message: bytes, 

653 conf_req_flag: bool, 

654 qop_req: int = GSS_C_QOP_DEFAULT, 

655 ): 

656 """ 

657 See GSS_WrapEx 

658 """ 

659 _msgs, signature = self.GSS_WrapEx( 

660 Context, 

661 [ 

662 self.WRAP_MSG( 

663 conf_req_flag=conf_req_flag, 

664 sign=True, 

665 data=input_message, 

666 ) 

667 ], 

668 qop_req=qop_req, 

669 ) 

670 if _msgs[0].data: 

671 signature /= _msgs[0].data 

672 return signature 

673 

674 # sect 2.3.4 

675 

676 def GSS_Unwrap( 

677 self, 

678 Context: CONTEXT, 

679 signature, 

680 ): 

681 """ 

682 See GSS_UnwrapEx 

683 """ 

684 data = b"" 

685 if signature.payload: 

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

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

688 if signature.payload.original: 

689 data = signature.payload.original 

690 else: 

691 data = bytes(signature.payload) 

692 signature = signature.copy() 

693 signature.remove_payload() 

694 return self.GSS_UnwrapEx( 

695 Context, 

696 [ 

697 self.WRAP_MSG( 

698 conf_req_flag=True, 

699 sign=True, 

700 data=data, 

701 ) 

702 ], 

703 signature, 

704 )[0].data 

705 

706 # MISC 

707 

708 def NegTokenInit2(self): 

709 """ 

710 Server-Initiation 

711 See [MS-SPNG] sect 3.2.5.2 

712 """ 

713 return None, None 

714 

715 def SupportsMechListMIC(self): 

716 """ 

717 Returns whether mechListMIC is supported or not 

718 """ 

719 return True 

720 

721 def GetMechListMIC(self, Context, input): 

722 """ 

723 Compute mechListMIC 

724 """ 

725 return self.GSS_GetMIC(Context, input) 

726 

727 def VerifyMechListMIC(self, Context, otherMIC, input): 

728 """ 

729 Verify mechListMIC 

730 """ 

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

732 

733 def LegsAmount(self, Context: CONTEXT): 

734 """ 

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

736 

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

738 """ 

739 return 2