Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
kex_gss.py687 linesDownload Raw Back to paramiko
1# Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>2# Copyright (C) 2013-2014 science + computing ag3# Author: Sebastian Deiss <sebastian.deiss@t-online.de>4#5#6# This file is part of paramiko.7#8# Paramiko is free software; you can redistribute it and/or modify it under the9# terms of the GNU Lesser General Public License as published by the Free10# Software Foundation; either version 2.1 of the License, or (at your option)11# any later version.12#13# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY14# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR15# A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more16# details.17#18# You should have received a copy of the GNU Lesser General Public License19# along with Paramiko; if not, write to the Free Software Foundation, Inc.,20# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.21 22 23"""24This module provides GSS-API / SSPI Key Exchange as defined in :rfc:`4462`.25 26.. note:: Credential delegation is not supported in server mode.27 28.. note::29    `RFC 4462 Section 2.230    <https://tools.ietf.org/html/rfc4462.html#section-2.2>`_ says we are not31    required to implement GSS-API error messages. Thus, in many methods within32    this module, if an error occurs an exception will be thrown and the33    connection will be terminated.34 35.. seealso:: :doc:`/api/ssh_gss`36 37.. versionadded:: 1.1538"""39 40import os41from hashlib import sha142 43from paramiko.common import (44    DEBUG,45    max_byte,46    zero_byte,47    byte_chr,48    byte_mask,49    byte_ord,50)51from paramiko import util52from paramiko.message import Message53from paramiko.ssh_exception import SSHException54 55 56(57    MSG_KEXGSS_INIT,58    MSG_KEXGSS_CONTINUE,59    MSG_KEXGSS_COMPLETE,60    MSG_KEXGSS_HOSTKEY,61    MSG_KEXGSS_ERROR,62) = range(30, 35)63(MSG_KEXGSS_GROUPREQ, MSG_KEXGSS_GROUP) = range(40, 42)64(65    c_MSG_KEXGSS_INIT,66    c_MSG_KEXGSS_CONTINUE,67    c_MSG_KEXGSS_COMPLETE,68    c_MSG_KEXGSS_HOSTKEY,69    c_MSG_KEXGSS_ERROR,70) = [byte_chr(c) for c in range(30, 35)]71(c_MSG_KEXGSS_GROUPREQ, c_MSG_KEXGSS_GROUP) = [72    byte_chr(c) for c in range(40, 42)73]74 75 76class KexGSSGroup1:77    """78    GSS-API / SSPI Authenticated Diffie-Hellman Key Exchange as defined in `RFC79    4462 Section 2 <https://tools.ietf.org/html/rfc4462.html#section-2>`_80    """81 82    # draft-ietf-secsh-transport-09.txt, page 1783    P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF  # noqa84    G = 285    b7fffffffffffffff = byte_chr(0x7F) + max_byte * 7  # noqa86    b0000000000000000 = zero_byte * 8  # noqa87    NAME = "gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g=="88 89    def __init__(self, transport):90        self.transport = transport91        self.kexgss = self.transport.kexgss_ctxt92        self.gss_host = None93        self.x = 094        self.e = 095        self.f = 096 97    def start_kex(self):98        """99        Start the GSS-API / SSPI Authenticated Diffie-Hellman Key Exchange.100        """101        self._generate_x()102        if self.transport.server_mode:103            # compute f = g^x mod p, but don't send it yet104            self.f = pow(self.G, self.x, self.P)105            self.transport._expect_packet(MSG_KEXGSS_INIT)106            return107        # compute e = g^x mod p (where g=2), and send it108        self.e = pow(self.G, self.x, self.P)109        # Initialize GSS-API Key Exchange110        self.gss_host = self.transport.gss_host111        m = Message()112        m.add_byte(c_MSG_KEXGSS_INIT)113        m.add_string(self.kexgss.ssh_init_sec_context(target=self.gss_host))114        m.add_mpint(self.e)115        self.transport._send_message(m)116        self.transport._expect_packet(117            MSG_KEXGSS_HOSTKEY,118            MSG_KEXGSS_CONTINUE,119            MSG_KEXGSS_COMPLETE,120            MSG_KEXGSS_ERROR,121        )122 123    def parse_next(self, ptype, m):124        """125        Parse the next packet.126 127        :param ptype: The (string) type of the incoming packet128        :param `.Message` m: The packet content129        """130        if self.transport.server_mode and (ptype == MSG_KEXGSS_INIT):131            return self._parse_kexgss_init(m)132        elif not self.transport.server_mode and (ptype == MSG_KEXGSS_HOSTKEY):133            return self._parse_kexgss_hostkey(m)134        elif self.transport.server_mode and (ptype == MSG_KEXGSS_CONTINUE):135            return self._parse_kexgss_continue(m)136        elif not self.transport.server_mode and (ptype == MSG_KEXGSS_COMPLETE):137            return self._parse_kexgss_complete(m)138        elif ptype == MSG_KEXGSS_ERROR:139            return self._parse_kexgss_error(m)140        msg = "GSS KexGroup1 asked to handle packet type {:d}"141        raise SSHException(msg.format(ptype))142 143    # ##  internals...144 145    def _generate_x(self):146        """147        generate an "x" (1 < x < q), where q is (p-1)/2.148        p is a 128-byte (1024-bit) number, where the first 64 bits are 1.149        therefore q can be approximated as a 2^1023.  we drop the subset of150        potential x where the first 63 bits are 1, because some of those will151        be larger than q (but this is a tiny tiny subset of potential x).152        """153        while 1:154            x_bytes = os.urandom(128)155            x_bytes = byte_mask(x_bytes[0], 0x7F) + x_bytes[1:]156            first = x_bytes[:8]157            if first not in (self.b7fffffffffffffff, self.b0000000000000000):158                break159        self.x = util.inflate_long(x_bytes)160 161    def _parse_kexgss_hostkey(self, m):162        """163        Parse the SSH2_MSG_KEXGSS_HOSTKEY message (client mode).164 165        :param `.Message` m: The content of the SSH2_MSG_KEXGSS_HOSTKEY message166        """167        # client mode168        host_key = m.get_string()169        self.transport.host_key = host_key170        sig = m.get_string()171        self.transport._verify_key(host_key, sig)172        self.transport._expect_packet(MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE)173 174    def _parse_kexgss_continue(self, m):175        """176        Parse the SSH2_MSG_KEXGSS_CONTINUE message.177 178        :param `.Message` m: The content of the SSH2_MSG_KEXGSS_CONTINUE179            message180        """181        if not self.transport.server_mode:182            srv_token = m.get_string()183            m = Message()184            m.add_byte(c_MSG_KEXGSS_CONTINUE)185            m.add_string(186                self.kexgss.ssh_init_sec_context(187                    target=self.gss_host, recv_token=srv_token188                )189            )190            self.transport.send_message(m)191            self.transport._expect_packet(192                MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE, MSG_KEXGSS_ERROR193            )194        else:195            pass196 197    def _parse_kexgss_complete(self, m):198        """199        Parse the SSH2_MSG_KEXGSS_COMPLETE message (client mode).200 201        :param `.Message` m: The content of the202            SSH2_MSG_KEXGSS_COMPLETE message203        """204        # client mode205        if self.transport.host_key is None:206            self.transport.host_key = NullHostKey()207        self.f = m.get_mpint()208        if (self.f < 1) or (self.f > self.P - 1):209            raise SSHException('Server kex "f" is out of range')210        mic_token = m.get_string()211        # This must be TRUE, if there is a GSS-API token in this message.212        bool = m.get_boolean()213        srv_token = None214        if bool:215            srv_token = m.get_string()216        K = pow(self.f, self.x, self.P)217        # okay, build up the hash H of218        # (V_C || V_S || I_C || I_S || K_S || e || f || K)219        hm = Message()220        hm.add(221            self.transport.local_version,222            self.transport.remote_version,223            self.transport.local_kex_init,224            self.transport.remote_kex_init,225        )226        hm.add_string(self.transport.host_key.__str__())227        hm.add_mpint(self.e)228        hm.add_mpint(self.f)229        hm.add_mpint(K)230        H = sha1(str(hm)).digest()231        self.transport._set_K_H(K, H)232        if srv_token is not None:233            self.kexgss.ssh_init_sec_context(234                target=self.gss_host, recv_token=srv_token235            )236            self.kexgss.ssh_check_mic(mic_token, H)237        else:238            self.kexgss.ssh_check_mic(mic_token, H)239        self.transport.gss_kex_used = True240        self.transport._activate_outbound()241 242    def _parse_kexgss_init(self, m):243        """244        Parse the SSH2_MSG_KEXGSS_INIT message (server mode).245 246        :param `.Message` m: The content of the SSH2_MSG_KEXGSS_INIT message247        """248        # server mode249        client_token = m.get_string()250        self.e = m.get_mpint()251        if (self.e < 1) or (self.e > self.P - 1):252            raise SSHException('Client kex "e" is out of range')253        K = pow(self.e, self.x, self.P)254        self.transport.host_key = NullHostKey()255        key = self.transport.host_key.__str__()256        # okay, build up the hash H of257        # (V_C || V_S || I_C || I_S || K_S || e || f || K)258        hm = Message()259        hm.add(260            self.transport.remote_version,261            self.transport.local_version,262            self.transport.remote_kex_init,263            self.transport.local_kex_init,264        )265        hm.add_string(key)266        hm.add_mpint(self.e)267        hm.add_mpint(self.f)268        hm.add_mpint(K)269        H = sha1(hm.asbytes()).digest()270        self.transport._set_K_H(K, H)271        srv_token = self.kexgss.ssh_accept_sec_context(272            self.gss_host, client_token273        )274        m = Message()275        if self.kexgss._gss_srv_ctxt_status:276            mic_token = self.kexgss.ssh_get_mic(277                self.transport.session_id, gss_kex=True278            )279            m.add_byte(c_MSG_KEXGSS_COMPLETE)280            m.add_mpint(self.f)281            m.add_string(mic_token)282            if srv_token is not None:283                m.add_boolean(True)284                m.add_string(srv_token)285            else:286                m.add_boolean(False)287            self.transport._send_message(m)288            self.transport.gss_kex_used = True289            self.transport._activate_outbound()290        else:291            m.add_byte(c_MSG_KEXGSS_CONTINUE)292            m.add_string(srv_token)293            self.transport._send_message(m)294            self.transport._expect_packet(295                MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE, MSG_KEXGSS_ERROR296            )297 298    def _parse_kexgss_error(self, m):299        """300        Parse the SSH2_MSG_KEXGSS_ERROR message (client mode).301        The server may send a GSS-API error message. if it does, we display302        the error by throwing an exception (client mode).303 304        :param `.Message` m: The content of the SSH2_MSG_KEXGSS_ERROR message305        :raise SSHException: Contains GSS-API major and minor status as well as306                             the error message and the language tag of the307                             message308        """309        maj_status = m.get_int()310        min_status = m.get_int()311        err_msg = m.get_string()312        m.get_string()  # we don't care about the language!313        raise SSHException(314            """GSS-API Error:315Major Status: {}316Minor Status: {}317Error Message: {}318""".format(319                maj_status, min_status, err_msg320            )321        )322 323 324class KexGSSGroup14(KexGSSGroup1):325    """326    GSS-API / SSPI Authenticated Diffie-Hellman Group14 Key Exchange as defined327    in `RFC 4462 Section 2328    <https://tools.ietf.org/html/rfc4462.html#section-2>`_329    """330 331    P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF  # noqa332    G = 2333    NAME = "gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g=="334 335 336class KexGSSGex:337    """338    GSS-API / SSPI Authenticated Diffie-Hellman Group Exchange as defined in339    `RFC 4462 Section 2 <https://tools.ietf.org/html/rfc4462.html#section-2>`_340    """341 342    NAME = "gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g=="343    min_bits = 1024344    max_bits = 8192345    preferred_bits = 2048346 347    def __init__(self, transport):348        self.transport = transport349        self.kexgss = self.transport.kexgss_ctxt350        self.gss_host = None351        self.p = None352        self.q = None353        self.g = None354        self.x = None355        self.e = None356        self.f = None357        self.old_style = False358 359    def start_kex(self):360        """361        Start the GSS-API / SSPI Authenticated Diffie-Hellman Group Exchange362        """363        if self.transport.server_mode:364            self.transport._expect_packet(MSG_KEXGSS_GROUPREQ)365            return366        # request a bit range: we accept (min_bits) to (max_bits), but prefer367        # (preferred_bits).  according to the spec, we shouldn't pull the368        # minimum up above 1024.369        self.gss_host = self.transport.gss_host370        m = Message()371        m.add_byte(c_MSG_KEXGSS_GROUPREQ)372        m.add_int(self.min_bits)373        m.add_int(self.preferred_bits)374        m.add_int(self.max_bits)375        self.transport._send_message(m)376        self.transport._expect_packet(MSG_KEXGSS_GROUP)377 378    def parse_next(self, ptype, m):379        """380        Parse the next packet.381 382        :param ptype: The (string) type of the incoming packet383        :param `.Message` m: The packet content384        """385        if ptype == MSG_KEXGSS_GROUPREQ:386            return self._parse_kexgss_groupreq(m)387        elif ptype == MSG_KEXGSS_GROUP:388            return self._parse_kexgss_group(m)389        elif ptype == MSG_KEXGSS_INIT:390            return self._parse_kexgss_gex_init(m)391        elif ptype == MSG_KEXGSS_HOSTKEY:392            return self._parse_kexgss_hostkey(m)393        elif ptype == MSG_KEXGSS_CONTINUE:394            return self._parse_kexgss_continue(m)395        elif ptype == MSG_KEXGSS_COMPLETE:396            return self._parse_kexgss_complete(m)397        elif ptype == MSG_KEXGSS_ERROR:398            return self._parse_kexgss_error(m)399        msg = "KexGex asked to handle packet type {:d}"400        raise SSHException(msg.format(ptype))401 402    # ##  internals...403 404    def _generate_x(self):405        # generate an "x" (1 < x < (p-1)/2).406        q = (self.p - 1) // 2407        qnorm = util.deflate_long(q, 0)408        qhbyte = byte_ord(qnorm[0])409        byte_count = len(qnorm)410        qmask = 0xFF411        while not (qhbyte & 0x80):412            qhbyte <<= 1413            qmask >>= 1414        while True:415            x_bytes = os.urandom(byte_count)416            x_bytes = byte_mask(x_bytes[0], qmask) + x_bytes[1:]417            x = util.inflate_long(x_bytes, 1)418            if (x > 1) and (x < q):419                break420        self.x = x421 422    def _parse_kexgss_groupreq(self, m):423        """424        Parse the SSH2_MSG_KEXGSS_GROUPREQ message (server mode).425 426        :param `.Message` m: The content of the427            SSH2_MSG_KEXGSS_GROUPREQ message428        """429        minbits = m.get_int()430        preferredbits = m.get_int()431        maxbits = m.get_int()432        # smoosh the user's preferred size into our own limits433        if preferredbits > self.max_bits:434            preferredbits = self.max_bits435        if preferredbits < self.min_bits:436            preferredbits = self.min_bits437        # fix min/max if they're inconsistent.  technically, we could just pout438        # and hang up, but there's no harm in giving them the benefit of the439        # doubt and just picking a bitsize for them.440        if minbits > preferredbits:441            minbits = preferredbits442        if maxbits < preferredbits:443            maxbits = preferredbits444        # now save a copy445        self.min_bits = minbits446        self.preferred_bits = preferredbits447        self.max_bits = maxbits448        # generate prime449        pack = self.transport._get_modulus_pack()450        if pack is None:451            raise SSHException("Can't do server-side gex with no modulus pack")452        self.transport._log(453            DEBUG,  # noqa454            "Picking p ({} <= {} <= {} bits)".format(455                minbits, preferredbits, maxbits456            ),457        )458        self.g, self.p = pack.get_modulus(minbits, preferredbits, maxbits)459        m = Message()460        m.add_byte(c_MSG_KEXGSS_GROUP)461        m.add_mpint(self.p)462        m.add_mpint(self.g)463        self.transport._send_message(m)464        self.transport._expect_packet(MSG_KEXGSS_INIT)465 466    def _parse_kexgss_group(self, m):467        """468        Parse the SSH2_MSG_KEXGSS_GROUP message (client mode).469 470        :param `Message` m: The content of the SSH2_MSG_KEXGSS_GROUP message471        """472        self.p = m.get_mpint()473        self.g = m.get_mpint()474        # reject if p's bit length < 1024 or > 8192475        bitlen = util.bit_length(self.p)476        if (bitlen < 1024) or (bitlen > 8192):477            raise SSHException(478                "Server-generated gex p (don't ask) is out of range "479                "({} bits)".format(bitlen)480            )481        self.transport._log(482            DEBUG, "Got server p ({} bits)".format(bitlen)483        )  # noqa484        self._generate_x()485        # now compute e = g^x mod p486        self.e = pow(self.g, self.x, self.p)487        m = Message()488        m.add_byte(c_MSG_KEXGSS_INIT)489        m.add_string(self.kexgss.ssh_init_sec_context(target=self.gss_host))490        m.add_mpint(self.e)491        self.transport._send_message(m)492        self.transport._expect_packet(493            MSG_KEXGSS_HOSTKEY,494            MSG_KEXGSS_CONTINUE,495            MSG_KEXGSS_COMPLETE,496            MSG_KEXGSS_ERROR,497        )498 499    def _parse_kexgss_gex_init(self, m):500        """501        Parse the SSH2_MSG_KEXGSS_INIT message (server mode).502 503        :param `Message` m: The content of the SSH2_MSG_KEXGSS_INIT message504        """505        client_token = m.get_string()506        self.e = m.get_mpint()507        if (self.e < 1) or (self.e > self.p - 1):508            raise SSHException('Client kex "e" is out of range')509        self._generate_x()510        self.f = pow(self.g, self.x, self.p)511        K = pow(self.e, self.x, self.p)512        self.transport.host_key = NullHostKey()513        key = self.transport.host_key.__str__()514        # okay, build up the hash H of515        # (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K)  # noqa516        hm = Message()517        hm.add(518            self.transport.remote_version,519            self.transport.local_version,520            self.transport.remote_kex_init,521            self.transport.local_kex_init,522            key,523        )524        hm.add_int(self.min_bits)525        hm.add_int(self.preferred_bits)526        hm.add_int(self.max_bits)527        hm.add_mpint(self.p)528        hm.add_mpint(self.g)529        hm.add_mpint(self.e)530        hm.add_mpint(self.f)531        hm.add_mpint(K)532        H = sha1(hm.asbytes()).digest()533        self.transport._set_K_H(K, H)534        srv_token = self.kexgss.ssh_accept_sec_context(535            self.gss_host, client_token536        )537        m = Message()538        if self.kexgss._gss_srv_ctxt_status:539            mic_token = self.kexgss.ssh_get_mic(540                self.transport.session_id, gss_kex=True541            )542            m.add_byte(c_MSG_KEXGSS_COMPLETE)543            m.add_mpint(self.f)544            m.add_string(mic_token)545            if srv_token is not None:546                m.add_boolean(True)547                m.add_string(srv_token)548            else:549                m.add_boolean(False)550            self.transport._send_message(m)551            self.transport.gss_kex_used = True552            self.transport._activate_outbound()553        else:554            m.add_byte(c_MSG_KEXGSS_CONTINUE)555            m.add_string(srv_token)556            self.transport._send_message(m)557            self.transport._expect_packet(558                MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE, MSG_KEXGSS_ERROR559            )560 561    def _parse_kexgss_hostkey(self, m):562        """563        Parse the SSH2_MSG_KEXGSS_HOSTKEY message (client mode).564 565        :param `Message` m: The content of the SSH2_MSG_KEXGSS_HOSTKEY message566        """567        # client mode568        host_key = m.get_string()569        self.transport.host_key = host_key570        sig = m.get_string()571        self.transport._verify_key(host_key, sig)572        self.transport._expect_packet(MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE)573 574    def _parse_kexgss_continue(self, m):575        """576        Parse the SSH2_MSG_KEXGSS_CONTINUE message.577 578        :param `Message` m: The content of the SSH2_MSG_KEXGSS_CONTINUE message579        """580        if not self.transport.server_mode:581            srv_token = m.get_string()582            m = Message()583            m.add_byte(c_MSG_KEXGSS_CONTINUE)584            m.add_string(585                self.kexgss.ssh_init_sec_context(586                    target=self.gss_host, recv_token=srv_token587                )588            )589            self.transport.send_message(m)590            self.transport._expect_packet(591                MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE, MSG_KEXGSS_ERROR592            )593        else:594            pass595 596    def _parse_kexgss_complete(self, m):597        """598        Parse the SSH2_MSG_KEXGSS_COMPLETE message (client mode).599 600        :param `Message` m: The content of the SSH2_MSG_KEXGSS_COMPLETE message601        """602        if self.transport.host_key is None:603            self.transport.host_key = NullHostKey()604        self.f = m.get_mpint()605        mic_token = m.get_string()606        # This must be TRUE, if there is a GSS-API token in this message.607        bool = m.get_boolean()608        srv_token = None609        if bool:610            srv_token = m.get_string()611        if (self.f < 1) or (self.f > self.p - 1):612            raise SSHException('Server kex "f" is out of range')613        K = pow(self.f, self.x, self.p)614        # okay, build up the hash H of615        # (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K)  # noqa616        hm = Message()617        hm.add(618            self.transport.local_version,619            self.transport.remote_version,620            self.transport.local_kex_init,621            self.transport.remote_kex_init,622            self.transport.host_key.__str__(),623        )624        if not self.old_style:625            hm.add_int(self.min_bits)626        hm.add_int(self.preferred_bits)627        if not self.old_style:628            hm.add_int(self.max_bits)629        hm.add_mpint(self.p)630        hm.add_mpint(self.g)631        hm.add_mpint(self.e)632        hm.add_mpint(self.f)633        hm.add_mpint(K)634        H = sha1(hm.asbytes()).digest()635        self.transport._set_K_H(K, H)636        if srv_token is not None:637            self.kexgss.ssh_init_sec_context(638                target=self.gss_host, recv_token=srv_token639            )640            self.kexgss.ssh_check_mic(mic_token, H)641        else:642            self.kexgss.ssh_check_mic(mic_token, H)643        self.transport.gss_kex_used = True644        self.transport._activate_outbound()645 646    def _parse_kexgss_error(self, m):647        """648        Parse the SSH2_MSG_KEXGSS_ERROR message (client mode).649        The server may send a GSS-API error message. if it does, we display650        the error by throwing an exception (client mode).651 652        :param `Message` m:  The content of the SSH2_MSG_KEXGSS_ERROR message653        :raise SSHException: Contains GSS-API major and minor status as well as654                             the error message and the language tag of the655                             message656        """657        maj_status = m.get_int()658        min_status = m.get_int()659        err_msg = m.get_string()660        m.get_string()  # we don't care about the language (lang_tag)!661        raise SSHException(662            """GSS-API Error:663Major Status: {}664Minor Status: {}665Error Message: {}666""".format(667                maj_status, min_status, err_msg668            )669        )670 671 672class NullHostKey:673    """674    This class represents the Null Host Key for GSS-API Key Exchange as defined675    in `RFC 4462 Section 5676    <https://tools.ietf.org/html/rfc4462.html#section-5>`_677    """678 679    def __init__(self):680        self.key = ""681 682    def __str__(self):683        return self.key684 685    def get_name(self):686        return self.key687 
codekingpro/portable-devtools · Team Ai