Exemplo n.º 1
0
 def encode_tlv(self, ident, val):
     # no need to support ident > 31 here
     self.content += byte_chr(ident)
     if len(val) > 0x7f:
         lenstr = util.deflate_long(len(val))
         self.content += byte_chr(0x80 + len(lenstr)) + lenstr
     else:
         self.content += byte_chr(len(val))
     self.content += val
Exemplo n.º 2
0
def safe_string(s):
    out = b''
    for c in s:
        i = byte_ord(c)
        if 32 <= i <= 127:
            out += byte_chr(i)
        else:
            out += b('%{:02X}'.format(i))
    return out
Exemplo n.º 3
0
"""
Ephemeral Elliptic Curve Diffie-Hellman (ECDH) key exchange
RFC 5656, Section 4
"""

from hashlib import sha256, sha384, sha512
from message import Message
from py3compat import byte_chr, long
from ssh_exception import SSHException
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
from binascii import hexlify

_MSG_KEXECDH_INIT, _MSG_KEXECDH_REPLY = range(30, 32)
c_MSG_KEXECDH_INIT, c_MSG_KEXECDH_REPLY = [byte_chr(c) for c in range(30, 32)]


class KexNistp256():

    name = "ecdh-sha2-nistp256"
    hash_algo = sha256
    curve = ec.SECP256R1()

    def __init__(self, transport):
        self.transport = transport
        # private key, client public and server public keys
        self.P = long(0)
        self.Q_C = None
        self.Q_S = None

    def start_kex(self):
Exemplo n.º 4
0
 def _send_packet(self, t, packet):
     packet = asbytes(packet)
     out = struct.pack('>I', len(packet) + 1) + byte_chr(t) + packet
     if self.ultra_debug:
         self._log(DEBUG, util.format_binary(out, 'OUT: '))
     self._write_all(out)
Exemplo n.º 5
0
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))
Exemplo n.º 6
0
import os
from hashlib import sha1

from common import DEBUG, max_byte, zero_byte
from . import util
from message import Message
from py3compat import byte_chr, byte_mask, byte_ord
from 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
Exemplo n.º 7
0
import os
from hashlib import sha1, sha256

from . import util
from common import DEBUG
from message import Message
from py3compat import byte_chr, byte_ord, byte_mask
from ssh_exception import SSHException


_MSG_KEXDH_GEX_REQUEST_OLD, _MSG_KEXDH_GEX_GROUP, _MSG_KEXDH_GEX_INIT, \
    _MSG_KEXDH_GEX_REPLY, _MSG_KEXDH_GEX_REQUEST = range(30, 35)

c_MSG_KEXDH_GEX_REQUEST_OLD, c_MSG_KEXDH_GEX_GROUP, c_MSG_KEXDH_GEX_INIT, \
    c_MSG_KEXDH_GEX_REPLY, c_MSG_KEXDH_GEX_REQUEST = \
    [byte_chr(c) for c in range(30, 35)]


class KexGex(object):

    name = 'diffie-hellman-group-exchange-sha1'
    min_bits = 1024
    max_bits = 8192
    preferred_bits = 2048
    hash_algo = sha1

    def __init__(self, transport):
        self.transport = transport
        self.p = None
        self.q = None
        self.g = None
Exemplo n.º 8
0
Standard SSH key exchange ("kex" if you wanna sound cool).  Diffie-Hellman of
1024 bit key halves, using a known "p" prime and "g" generator.
"""

import os
from hashlib import sha1

from . import util
from common import max_byte, zero_byte
from message import Message
from py3compat import byte_chr, long, byte_mask
from ssh_exception import SSHException


_MSG_KEXDH_INIT, _MSG_KEXDH_REPLY = range(30, 32)
c_MSG_KEXDH_INIT, c_MSG_KEXDH_REPLY = [byte_chr(c) for c in range(30, 32)]

b7fffffffffffffff = byte_chr(0x7f) + max_byte * 7
b0000000000000000 = zero_byte * 8


class KexGroup1(object):

    # draft-ietf-secsh-transport-09.txt, page 17
    P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF  # noqa
    G = 2

    name = 'diffie-hellman-group1-sha1'
    hash_algo = sha1

    def __init__(self, transport):
Exemplo n.º 9
0
MSG_KEXINIT, MSG_NEWKEYS = range(20, 22)
MSG_USERAUTH_REQUEST, MSG_USERAUTH_FAILURE, MSG_USERAUTH_SUCCESS, \
    MSG_USERAUTH_BANNER = range(50, 54)
MSG_USERAUTH_PK_OK = 60
MSG_USERAUTH_INFO_REQUEST, MSG_USERAUTH_INFO_RESPONSE = range(60, 62)
MSG_USERAUTH_GSSAPI_RESPONSE, MSG_USERAUTH_GSSAPI_TOKEN = range(60, 62)
MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, MSG_USERAUTH_GSSAPI_ERROR,\
    MSG_USERAUTH_GSSAPI_ERRTOK, MSG_USERAUTH_GSSAPI_MIC = range(63, 67)
HIGHEST_USERAUTH_MESSAGE_ID = 79
MSG_GLOBAL_REQUEST, MSG_REQUEST_SUCCESS, MSG_REQUEST_FAILURE = range(80, 83)
MSG_CHANNEL_OPEN, MSG_CHANNEL_OPEN_SUCCESS, MSG_CHANNEL_OPEN_FAILURE, \
    MSG_CHANNEL_WINDOW_ADJUST, MSG_CHANNEL_DATA, MSG_CHANNEL_EXTENDED_DATA, \
    MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST, \
    MSG_CHANNEL_SUCCESS, MSG_CHANNEL_FAILURE = range(90, 101)

cMSG_DISCONNECT = byte_chr(MSG_DISCONNECT)
cMSG_IGNORE = byte_chr(MSG_IGNORE)
cMSG_UNIMPLEMENTED = byte_chr(MSG_UNIMPLEMENTED)
cMSG_DEBUG = byte_chr(MSG_DEBUG)
cMSG_SERVICE_REQUEST = byte_chr(MSG_SERVICE_REQUEST)
cMSG_SERVICE_ACCEPT = byte_chr(MSG_SERVICE_ACCEPT)
cMSG_KEXINIT = byte_chr(MSG_KEXINIT)
cMSG_NEWKEYS = byte_chr(MSG_NEWKEYS)
cMSG_USERAUTH_REQUEST = byte_chr(MSG_USERAUTH_REQUEST)
cMSG_USERAUTH_FAILURE = byte_chr(MSG_USERAUTH_FAILURE)
cMSG_USERAUTH_SUCCESS = byte_chr(MSG_USERAUTH_SUCCESS)
cMSG_USERAUTH_BANNER = byte_chr(MSG_USERAUTH_BANNER)
cMSG_USERAUTH_PK_OK = byte_chr(MSG_USERAUTH_PK_OK)
cMSG_USERAUTH_INFO_REQUEST = byte_chr(MSG_USERAUTH_INFO_REQUEST)
cMSG_USERAUTH_INFO_RESPONSE = byte_chr(MSG_USERAUTH_INFO_RESPONSE)
cMSG_USERAUTH_GSSAPI_RESPONSE = byte_chr(MSG_USERAUTH_GSSAPI_RESPONSE)
Exemplo n.º 10
0
import struct
import sys
import threading
import time
import tempfile
import stat
from select import select
from common import asbytes, io_sleep
from py3compat import byte_chr

from ssh_exception import SSHException, AuthenticationException
from message import Message
from pkey import PKey
from util import retry_on_signal

cSSH2_AGENTC_REQUEST_IDENTITIES = byte_chr(11)
SSH2_AGENT_IDENTITIES_ANSWER = 12
cSSH2_AGENTC_SIGN_REQUEST = byte_chr(13)
SSH2_AGENT_SIGN_RESPONSE = 14


class AgentSSH(object):
    def __init__(self):
        self._conn = None
        self._keys = ()

    def get_keys(self):
        """
        Return the list of keys available through the SSH agent, if any.  If
        no SSH agent was running (or it couldn't be contacted), an empty list
        will be returned.