123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680 |
- # Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
- # Copyright (C) 2013-2014 science + computing ag
- # Author: Sebastian Deiss <sebastian.deiss@t-online.de>
- #
- #
- # This file is part of paramiko.
- #
- # Paramiko is free software; you can redistribute it and/or modify it under the
- # terms of the GNU Lesser General Public License as published by the Free
- # Software Foundation; either version 2.1 of the License, or (at your option)
- # any later version.
- #
- # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
- # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
- # details.
- #
- # You should have received a copy of the GNU Lesser General Public License
- # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
- # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- """
- This module provides GSS-API / SSPI Key Exchange as defined in :rfc:`4462`.
- .. note:: Credential delegation is not supported in server mode.
- .. note::
- `RFC 4462 Section 2.2
- <https://tools.ietf.org/html/rfc4462.html#section-2.2>`_ says we are not
- required to implement GSS-API error messages. Thus, in many methods within
- this module, if an error occurs an exception will be thrown and the
- connection will be terminated.
- .. seealso:: :doc:`/api/ssh_gss`
- .. versionadded:: 1.15
- """
- import os
- from hashlib import sha1
- from paramiko.common import DEBUG, max_byte, zero_byte
- from paramiko import util
- from paramiko.message import Message
- from paramiko.py3compat import byte_chr, byte_mask, byte_ord
- from paramiko.ssh_exception import SSHException
- (
- MSG_KEXGSS_INIT,
- MSG_KEXGSS_CONTINUE,
- MSG_KEXGSS_COMPLETE,
- MSG_KEXGSS_HOSTKEY,
- MSG_KEXGSS_ERROR,
- ) = range(30, 35)
- (MSG_KEXGSS_GROUPREQ, MSG_KEXGSS_GROUP) = range(40, 42)
- (
- c_MSG_KEXGSS_INIT,
- c_MSG_KEXGSS_CONTINUE,
- c_MSG_KEXGSS_COMPLETE,
- c_MSG_KEXGSS_HOSTKEY,
- c_MSG_KEXGSS_ERROR,
- ) = [byte_chr(c) for c in range(30, 35)]
- (c_MSG_KEXGSS_GROUPREQ, c_MSG_KEXGSS_GROUP) = [
- byte_chr(c) for c in range(40, 42)
- ]
- class KexGSSGroup1(object):
- """
- GSS-API / SSPI Authenticated Diffie-Hellman Key Exchange as defined in `RFC
- 4462 Section 2 <https://tools.ietf.org/html/rfc4462.html#section-2>`_
- """
- # draft-ietf-secsh-transport-09.txt, page 17
- P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF # noqa
- G = 2
- b7fffffffffffffff = byte_chr(0x7f) + max_byte * 7 # noqa
- b0000000000000000 = zero_byte * 8 # noqa
- NAME = "gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g=="
- def __init__(self, transport):
- self.transport = transport
- self.kexgss = self.transport.kexgss_ctxt
- self.gss_host = None
- self.x = 0
- self.e = 0
- self.f = 0
- def start_kex(self):
- """
- Start the GSS-API / SSPI Authenticated Diffie-Hellman Key Exchange.
- """
- self._generate_x()
- if self.transport.server_mode:
- # compute f = g^x mod p, but don't send it yet
- self.f = pow(self.G, self.x, self.P)
- self.transport._expect_packet(MSG_KEXGSS_INIT)
- return
- # compute e = g^x mod p (where g=2), and send it
- self.e = pow(self.G, self.x, self.P)
- # Initialize GSS-API Key Exchange
- self.gss_host = self.transport.gss_host
- m = Message()
- m.add_byte(c_MSG_KEXGSS_INIT)
- m.add_string(self.kexgss.ssh_init_sec_context(target=self.gss_host))
- m.add_mpint(self.e)
- self.transport._send_message(m)
- self.transport._expect_packet(
- MSG_KEXGSS_HOSTKEY,
- MSG_KEXGSS_CONTINUE,
- MSG_KEXGSS_COMPLETE,
- MSG_KEXGSS_ERROR,
- )
- def parse_next(self, ptype, m):
- """
- Parse the next packet.
- :param ptype: The (string) type of the incoming packet
- :param `.Message` m: The paket content
- """
- if self.transport.server_mode and (ptype == MSG_KEXGSS_INIT):
- return self._parse_kexgss_init(m)
- elif not self.transport.server_mode and (ptype == MSG_KEXGSS_HOSTKEY):
- return self._parse_kexgss_hostkey(m)
- elif self.transport.server_mode and (ptype == MSG_KEXGSS_CONTINUE):
- return self._parse_kexgss_continue(m)
- elif not self.transport.server_mode and (ptype == MSG_KEXGSS_COMPLETE):
- return self._parse_kexgss_complete(m)
- elif ptype == MSG_KEXGSS_ERROR:
- return self._parse_kexgss_error(m)
- msg = "GSS KexGroup1 asked to handle packet type {:d}"
- raise SSHException(msg.format(ptype))
- # ## internals...
- def _generate_x(self):
- """
- generate an "x" (1 < x < q), where q is (p-1)/2.
- p is a 128-byte (1024-bit) number, where the first 64 bits are 1.
- therefore q can be approximated as a 2^1023. we drop the subset of
- potential x where the first 63 bits are 1, because some of those will
- be larger than q (but this is a tiny tiny subset of potential x).
- """
- while 1:
- x_bytes = os.urandom(128)
- x_bytes = byte_mask(x_bytes[0], 0x7f) + x_bytes[1:]
- first = x_bytes[:8]
- if first not in (self.b7fffffffffffffff, self.b0000000000000000):
- break
- self.x = util.inflate_long(x_bytes)
- def _parse_kexgss_hostkey(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_HOSTKEY message (client mode).
- :param `.Message` m: The content of the SSH2_MSG_KEXGSS_HOSTKEY message
- """
- # client mode
- host_key = m.get_string()
- self.transport.host_key = host_key
- sig = m.get_string()
- self.transport._verify_key(host_key, sig)
- self.transport._expect_packet(MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE)
- def _parse_kexgss_continue(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_CONTINUE message.
- :param `.Message` m: The content of the SSH2_MSG_KEXGSS_CONTINUE
- message
- """
- if not self.transport.server_mode:
- srv_token = m.get_string()
- m = Message()
- m.add_byte(c_MSG_KEXGSS_CONTINUE)
- m.add_string(
- self.kexgss.ssh_init_sec_context(
- target=self.gss_host, recv_token=srv_token
- )
- )
- self.transport.send_message(m)
- self.transport._expect_packet(
- MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE, MSG_KEXGSS_ERROR
- )
- else:
- pass
- def _parse_kexgss_complete(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_COMPLETE message (client mode).
- :param `.Message` m: The content of the
- SSH2_MSG_KEXGSS_COMPLETE message
- """
- # client mode
- if self.transport.host_key is None:
- self.transport.host_key = NullHostKey()
- self.f = m.get_mpint()
- if (self.f < 1) or (self.f > self.P - 1):
- raise SSHException('Server kex "f" is out of range')
- mic_token = m.get_string()
- # This must be TRUE, if there is a GSS-API token in this message.
- bool = m.get_boolean()
- srv_token = None
- if bool:
- srv_token = m.get_string()
- K = pow(self.f, self.x, self.P)
- # okay, build up the hash H of
- # (V_C || V_S || I_C || I_S || K_S || e || f || K)
- hm = Message()
- hm.add(
- self.transport.local_version,
- self.transport.remote_version,
- self.transport.local_kex_init,
- self.transport.remote_kex_init,
- )
- hm.add_string(self.transport.host_key.__str__())
- hm.add_mpint(self.e)
- hm.add_mpint(self.f)
- hm.add_mpint(K)
- H = sha1(str(hm)).digest()
- self.transport._set_K_H(K, H)
- if srv_token is not None:
- self.kexgss.ssh_init_sec_context(
- target=self.gss_host, recv_token=srv_token
- )
- self.kexgss.ssh_check_mic(mic_token, H)
- else:
- self.kexgss.ssh_check_mic(mic_token, H)
- self.transport.gss_kex_used = True
- self.transport._activate_outbound()
- def _parse_kexgss_init(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_INIT message (server mode).
- :param `.Message` m: The content of the SSH2_MSG_KEXGSS_INIT message
- """
- # server mode
- client_token = m.get_string()
- self.e = m.get_mpint()
- if (self.e < 1) or (self.e > self.P - 1):
- raise SSHException('Client kex "e" is out of range')
- K = pow(self.e, self.x, self.P)
- self.transport.host_key = NullHostKey()
- key = self.transport.host_key.__str__()
- # okay, build up the hash H of
- # (V_C || V_S || I_C || I_S || K_S || e || f || K)
- hm = Message()
- hm.add(
- self.transport.remote_version,
- self.transport.local_version,
- self.transport.remote_kex_init,
- self.transport.local_kex_init,
- )
- hm.add_string(key)
- hm.add_mpint(self.e)
- hm.add_mpint(self.f)
- hm.add_mpint(K)
- H = sha1(hm.asbytes()).digest()
- self.transport._set_K_H(K, H)
- srv_token = self.kexgss.ssh_accept_sec_context(
- self.gss_host, client_token
- )
- m = Message()
- if self.kexgss._gss_srv_ctxt_status:
- mic_token = self.kexgss.ssh_get_mic(
- self.transport.session_id, gss_kex=True
- )
- m.add_byte(c_MSG_KEXGSS_COMPLETE)
- m.add_mpint(self.f)
- m.add_string(mic_token)
- if srv_token is not None:
- m.add_boolean(True)
- m.add_string(srv_token)
- else:
- m.add_boolean(False)
- self.transport._send_message(m)
- self.transport.gss_kex_used = True
- self.transport._activate_outbound()
- else:
- m.add_byte(c_MSG_KEXGSS_CONTINUE)
- m.add_string(srv_token)
- self.transport._send_message(m)
- self.transport._expect_packet(
- MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE, MSG_KEXGSS_ERROR
- )
- def _parse_kexgss_error(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_ERROR message (client mode).
- The server may send a GSS-API error message. if it does, we display
- the error by throwing an exception (client mode).
- :param `.Message` m: The content of the SSH2_MSG_KEXGSS_ERROR message
- :raise SSHException: Contains GSS-API major and minor status as well as
- the error message and the language tag of the
- message
- """
- maj_status = m.get_int()
- min_status = m.get_int()
- err_msg = m.get_string()
- m.get_string() # we don't care about the language!
- raise SSHException(
- """GSS-API Error:
- Major Status: {}
- Minor Status: {}
- Error Message: {}
- """.format(
- maj_status, min_status, err_msg
- )
- )
- class KexGSSGroup14(KexGSSGroup1):
- """
- GSS-API / SSPI Authenticated Diffie-Hellman Group14 Key Exchange as defined
- in `RFC 4462 Section 2
- <https://tools.ietf.org/html/rfc4462.html#section-2>`_
- """
- P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF # noqa
- G = 2
- NAME = "gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g=="
- class KexGSSGex(object):
- """
- GSS-API / SSPI Authenticated Diffie-Hellman Group Exchange as defined in
- `RFC 4462 Section 2 <https://tools.ietf.org/html/rfc4462.html#section-2>`_
- """
- NAME = "gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g=="
- min_bits = 1024
- max_bits = 8192
- preferred_bits = 2048
- def __init__(self, transport):
- self.transport = transport
- self.kexgss = self.transport.kexgss_ctxt
- self.gss_host = None
- self.p = None
- self.q = None
- self.g = None
- self.x = None
- self.e = None
- self.f = None
- self.old_style = False
- def start_kex(self):
- """
- Start the GSS-API / SSPI Authenticated Diffie-Hellman Group Exchange
- """
- if self.transport.server_mode:
- self.transport._expect_packet(MSG_KEXGSS_GROUPREQ)
- return
- # request a bit range: we accept (min_bits) to (max_bits), but prefer
- # (preferred_bits). according to the spec, we shouldn't pull the
- # minimum up above 1024.
- self.gss_host = self.transport.gss_host
- m = Message()
- m.add_byte(c_MSG_KEXGSS_GROUPREQ)
- m.add_int(self.min_bits)
- m.add_int(self.preferred_bits)
- m.add_int(self.max_bits)
- self.transport._send_message(m)
- self.transport._expect_packet(MSG_KEXGSS_GROUP)
- def parse_next(self, ptype, m):
- """
- Parse the next packet.
- :param ptype: The (string) type of the incoming packet
- :param `.Message` m: The paket content
- """
- if ptype == MSG_KEXGSS_GROUPREQ:
- return self._parse_kexgss_groupreq(m)
- elif ptype == MSG_KEXGSS_GROUP:
- return self._parse_kexgss_group(m)
- elif ptype == MSG_KEXGSS_INIT:
- return self._parse_kexgss_gex_init(m)
- elif ptype == MSG_KEXGSS_HOSTKEY:
- return self._parse_kexgss_hostkey(m)
- elif ptype == MSG_KEXGSS_CONTINUE:
- return self._parse_kexgss_continue(m)
- elif ptype == MSG_KEXGSS_COMPLETE:
- return self._parse_kexgss_complete(m)
- elif ptype == MSG_KEXGSS_ERROR:
- return self._parse_kexgss_error(m)
- msg = "KexGex asked to handle packet type {:d}"
- raise SSHException(msg.format(ptype))
- # ## internals...
- def _generate_x(self):
- # generate an "x" (1 < x < (p-1)/2).
- q = (self.p - 1) // 2
- qnorm = util.deflate_long(q, 0)
- qhbyte = byte_ord(qnorm[0])
- byte_count = len(qnorm)
- qmask = 0xff
- while not (qhbyte & 0x80):
- qhbyte <<= 1
- qmask >>= 1
- while True:
- x_bytes = os.urandom(byte_count)
- x_bytes = byte_mask(x_bytes[0], qmask) + x_bytes[1:]
- x = util.inflate_long(x_bytes, 1)
- if (x > 1) and (x < q):
- break
- self.x = x
- def _parse_kexgss_groupreq(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_GROUPREQ message (server mode).
- :param `.Message` m: The content of the
- SSH2_MSG_KEXGSS_GROUPREQ message
- """
- minbits = m.get_int()
- preferredbits = m.get_int()
- maxbits = m.get_int()
- # smoosh the user's preferred size into our own limits
- if preferredbits > self.max_bits:
- preferredbits = self.max_bits
- if preferredbits < self.min_bits:
- preferredbits = self.min_bits
- # fix min/max if they're inconsistent. technically, we could just pout
- # and hang up, but there's no harm in giving them the benefit of the
- # doubt and just picking a bitsize for them.
- if minbits > preferredbits:
- minbits = preferredbits
- if maxbits < preferredbits:
- maxbits = preferredbits
- # now save a copy
- self.min_bits = minbits
- self.preferred_bits = preferredbits
- self.max_bits = maxbits
- # generate prime
- pack = self.transport._get_modulus_pack()
- if pack is None:
- raise SSHException("Can't do server-side gex with no modulus pack")
- self.transport._log(
- DEBUG, # noqa
- "Picking p ({} <= {} <= {} bits)".format(
- minbits, preferredbits, maxbits
- ),
- )
- self.g, self.p = pack.get_modulus(minbits, preferredbits, maxbits)
- m = Message()
- m.add_byte(c_MSG_KEXGSS_GROUP)
- m.add_mpint(self.p)
- m.add_mpint(self.g)
- self.transport._send_message(m)
- self.transport._expect_packet(MSG_KEXGSS_INIT)
- def _parse_kexgss_group(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_GROUP message (client mode).
- :param `Message` m: The content of the SSH2_MSG_KEXGSS_GROUP message
- """
- self.p = m.get_mpint()
- self.g = m.get_mpint()
- # reject if p's bit length < 1024 or > 8192
- bitlen = util.bit_length(self.p)
- if (bitlen < 1024) or (bitlen > 8192):
- raise SSHException(
- "Server-generated gex p (don't ask) is out of range "
- "({} bits)".format(bitlen)
- )
- self.transport._log(
- DEBUG, "Got server p ({} bits)".format(bitlen)
- ) # noqa
- self._generate_x()
- # now compute e = g^x mod p
- self.e = pow(self.g, self.x, self.p)
- m = Message()
- m.add_byte(c_MSG_KEXGSS_INIT)
- m.add_string(self.kexgss.ssh_init_sec_context(target=self.gss_host))
- m.add_mpint(self.e)
- self.transport._send_message(m)
- self.transport._expect_packet(
- MSG_KEXGSS_HOSTKEY,
- MSG_KEXGSS_CONTINUE,
- MSG_KEXGSS_COMPLETE,
- MSG_KEXGSS_ERROR,
- )
- def _parse_kexgss_gex_init(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_INIT message (server mode).
- :param `Message` m: The content of the SSH2_MSG_KEXGSS_INIT message
- """
- client_token = m.get_string()
- self.e = m.get_mpint()
- if (self.e < 1) or (self.e > self.p - 1):
- raise SSHException('Client kex "e" is out of range')
- self._generate_x()
- self.f = pow(self.g, self.x, self.p)
- K = pow(self.e, self.x, self.p)
- self.transport.host_key = NullHostKey()
- key = self.transport.host_key.__str__()
- # okay, build up the hash H of
- # (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K) # noqa
- hm = Message()
- hm.add(
- self.transport.remote_version,
- self.transport.local_version,
- self.transport.remote_kex_init,
- self.transport.local_kex_init,
- key,
- )
- hm.add_int(self.min_bits)
- hm.add_int(self.preferred_bits)
- hm.add_int(self.max_bits)
- hm.add_mpint(self.p)
- hm.add_mpint(self.g)
- hm.add_mpint(self.e)
- hm.add_mpint(self.f)
- hm.add_mpint(K)
- H = sha1(hm.asbytes()).digest()
- self.transport._set_K_H(K, H)
- srv_token = self.kexgss.ssh_accept_sec_context(
- self.gss_host, client_token
- )
- m = Message()
- if self.kexgss._gss_srv_ctxt_status:
- mic_token = self.kexgss.ssh_get_mic(
- self.transport.session_id, gss_kex=True
- )
- m.add_byte(c_MSG_KEXGSS_COMPLETE)
- m.add_mpint(self.f)
- m.add_string(mic_token)
- if srv_token is not None:
- m.add_boolean(True)
- m.add_string(srv_token)
- else:
- m.add_boolean(False)
- self.transport._send_message(m)
- self.transport.gss_kex_used = True
- self.transport._activate_outbound()
- else:
- m.add_byte(c_MSG_KEXGSS_CONTINUE)
- m.add_string(srv_token)
- self.transport._send_message(m)
- self.transport._expect_packet(
- MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE, MSG_KEXGSS_ERROR
- )
- def _parse_kexgss_hostkey(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_HOSTKEY message (client mode).
- :param `Message` m: The content of the SSH2_MSG_KEXGSS_HOSTKEY message
- """
- # client mode
- host_key = m.get_string()
- self.transport.host_key = host_key
- sig = m.get_string()
- self.transport._verify_key(host_key, sig)
- self.transport._expect_packet(MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE)
- def _parse_kexgss_continue(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_CONTINUE message.
- :param `Message` m: The content of the SSH2_MSG_KEXGSS_CONTINUE message
- """
- if not self.transport.server_mode:
- srv_token = m.get_string()
- m = Message()
- m.add_byte(c_MSG_KEXGSS_CONTINUE)
- m.add_string(
- self.kexgss.ssh_init_sec_context(
- target=self.gss_host, recv_token=srv_token
- )
- )
- self.transport.send_message(m)
- self.transport._expect_packet(
- MSG_KEXGSS_CONTINUE, MSG_KEXGSS_COMPLETE, MSG_KEXGSS_ERROR
- )
- else:
- pass
- def _parse_kexgss_complete(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_COMPLETE message (client mode).
- :param `Message` m: The content of the SSH2_MSG_KEXGSS_COMPLETE message
- """
- if self.transport.host_key is None:
- self.transport.host_key = NullHostKey()
- self.f = m.get_mpint()
- mic_token = m.get_string()
- # This must be TRUE, if there is a GSS-API token in this message.
- bool = m.get_boolean()
- srv_token = None
- if bool:
- srv_token = m.get_string()
- if (self.f < 1) or (self.f > self.p - 1):
- raise SSHException('Server kex "f" is out of range')
- K = pow(self.f, self.x, self.p)
- # okay, build up the hash H of
- # (V_C || V_S || I_C || I_S || K_S || min || n || max || p || g || e || f || K) # noqa
- hm = Message()
- hm.add(
- self.transport.local_version,
- self.transport.remote_version,
- self.transport.local_kex_init,
- self.transport.remote_kex_init,
- self.transport.host_key.__str__(),
- )
- if not self.old_style:
- hm.add_int(self.min_bits)
- hm.add_int(self.preferred_bits)
- if not self.old_style:
- hm.add_int(self.max_bits)
- hm.add_mpint(self.p)
- hm.add_mpint(self.g)
- hm.add_mpint(self.e)
- hm.add_mpint(self.f)
- hm.add_mpint(K)
- H = sha1(hm.asbytes()).digest()
- self.transport._set_K_H(K, H)
- if srv_token is not None:
- self.kexgss.ssh_init_sec_context(
- target=self.gss_host, recv_token=srv_token
- )
- self.kexgss.ssh_check_mic(mic_token, H)
- else:
- self.kexgss.ssh_check_mic(mic_token, H)
- self.transport.gss_kex_used = True
- self.transport._activate_outbound()
- def _parse_kexgss_error(self, m):
- """
- Parse the SSH2_MSG_KEXGSS_ERROR message (client mode).
- The server may send a GSS-API error message. if it does, we display
- the error by throwing an exception (client mode).
- :param `Message` m: The content of the SSH2_MSG_KEXGSS_ERROR message
- :raise SSHException: Contains GSS-API major and minor status as well as
- the error message and the language tag of the
- message
- """
- maj_status = m.get_int()
- min_status = m.get_int()
- err_msg = m.get_string()
- m.get_string() # we don't care about the language (lang_tag)!
- raise SSHException(
- """GSS-API Error:
- Major Status: {}
- Minor Status: {}
- Error Message: {}
- """.format(
- maj_status, min_status, err_msg
- )
- )
- class NullHostKey(object):
- """
- This class represents the Null Host Key for GSS-API Key Exchange as defined
- in `RFC 4462 Section 5
- <https://tools.ietf.org/html/rfc4462.html#section-5>`_
- """
- def __init__(self):
- self.key = ""
- def __str__(self):
- return self.key
- def get_name(self):
- return self.key
|