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
def handler_13(self, msg): # SSH2_AGENTC_SIGN_REQUEST = 13 pkey, comment = self.server.identities.get(msg.get_binary(), (None, None)) data = msg.get_binary() msg.get_int() m = Message() if not pkey: m.add_byte(byte_chr(SSH_AGENT_FAILURE)) return m m.add_byte(byte_chr(SSH2_AGENT_SIGN_RESPONSE)) m.add_string(pkey.sign_ssh_data(data).asbytes()) return m
def send_ext_data(self, data): m = Message() m.add_byte(byte_chr(SSH2_MSG_CHANNEL_EXTENDED_DATA)) m.add_int(self.channel.remote_chanid) m.add_int(SSH2_EXTENDED_DATA_STDERR) m.add_string(data) self.channel.transport._send_user_message(m)
def _send_packet(self, t, packet): #self._log(DEBUG2, 'write: %s (len=%d)' % (CMD_NAMES.get(t, '0x%02x' % t), len(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)
def test_handle_13(self): # Test handling a SSH2_AGENTC_SIGN_REQUEST msg = Message() # Please sign some data msg.add_byte(byte_chr(13)) # The id of the key to sign with key = list(self.agent.identities.values())[0][0].asbytes() msg.add_int(len(key)) msg.add_bytes(bytes(key)) # A blob of binary to sign blob = b'\x0e' * 10 msg.add_int(len(blob)) msg.add_bytes(blob) # Go go go mtype, msg = self.send(msg) self.assertEqual(mtype, 14) self.assertEqual(binascii.hexlify(msg.get_binary()), force_bytes(( '000000077373682d7273610000010031d4c2bfad183557a7055f005c3d0d838d5' '701bd7b8a09d6d7f06699c691842c18e2bb62504a4beba0fbf5aeaf62f8106352' 'b99f60d1fdc2dac1f5ad29566022eff25f62fac38cb2db849ed6b862af5e6bd36' '09b249a099848aa6fcfdfe1d93d2538ab4e614ecc95a4282abf8742c7bb591db9' '3e049e70a559d29134d207018a650b77fd9a7b6be8a2b1f75efbd66fa5a1e9e96' '3a5245ebe76294e0d150dfa2348bc7303203263b11952f0300e7b3a9efab81827' 'b9e53d8c1cb8b2a1551c22cbab9e747fcff79bf57373f7ec8cb2a0dc9b42a7264' 'afa4b7913693b709c5418eda02175b0a183549643127be92e79936ffc91479629' 'c2acdc6aa5c83250a8edfe' )))
def _send_sign_data(self, msg): logger.debug('Sending signed data...') blob = msg.get_string() data = msg.get_string() flags = msg.get_int() logger.debug('Key blob:') for l in hexdump.hexdump(blob, result='generator'): logger.debug(l) # logger.debug('Data to be signed:') # for l in hexdump.hexdump(data, result='generator'): # logger.debug(l) # # logger.debug('Flags: %X', flags) signed_data = self._sign_data(blob, data) if not signed_data: self._send_failure() return sign_blob = Message() sign_blob.add_string('ssh-rsa') sign_blob.add_string(signed_data) msg = Message() # add response byte msg.add_byte(byte_chr(SSH_AGENT_SIGN_RESPONSE)) # add signed blob msg.add_string(sign_blob.asbytes()) self._send_reply(msg)
def test_removekey(self, mock_agent): agent = mock_agent.return_value agent._send_message.return_value = (SSH_AGENT_SUCCESS, byte_chr(SSH_AGENT_SUCCESS)) sc = SmartCardSSH() self.assertIsNone(sc.remove_key(False))
def test_addkey(self, mock_agent): agent = mock_agent.return_value agent._send_message.return_value = (SSH_AGENT_SUCCESS, byte_chr(SSH_AGENT_SUCCESS)) sc = SmartCardSSH() self.assertIsNone(sc.add_key('123456', True, False))
def handler_11(self, msg): # SSH2_AGENTC_REQUEST_IDENTITIES = 11 m = Message() m.add_byte(byte_chr(SSH2_AGENT_IDENTITIES_ANSWER)) m.add_int(len(self.server.identities)) for pkey, comment in self.server.identities.values(): m.add_string(pkey.asbytes()) m.add_string(comment) return m
def test_smart_card(self, mock_agent): agent = mock_agent.return_value agent._send_message.return_value = (SSH_AGENT_SUCCESS, byte_chr(SSH_AGENT_SUCCESS)) sc = SmartCardSSH() result = sc._smart_card(SSH_AGENTC_ADD_SMARTCARD_KEY, '123456') self.assertEqual(result, SSH_AGENT_SUCCESS)
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
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' % i) return out
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
def __call__(self): """Increament the counter and return the new value""" i = self.blocksize - 1 while i > -1: c = self.value[i] = byte_chr((byte_ord(self.value[i]) + 1) % 256) if c != zero_byte: return self.value.tostring() i -= 1 # counter reset x = deflate_long(self.overflow, add_sign_padding=False) self.value = array.array('c', zero_byte * (self.blocksize - len(x)) + x) return self.value.tostring()
def test_handle_11(self): # Test handling a SSH2_AGENTC_REQUEST_IDENTITIES msg = Message() msg.add_byte(byte_chr(11)) mtype, msg = self.send(msg) self.assertEqual(mtype, 12) # There should be one identity in the list self.assertEqual(msg.get_int(), 1) # It should be our identity pkey, comment = list(self.agent.identities.values())[0] self.assertEqual(msg.get_binary(), pkey.asbytes()) self.assertEqual(msg.get_string(), b'id_rsa_test')
def test_8_sign_rsa(self): # verify that the rsa private key can sign and verify key = RSAKey.from_private_key_file(test_path('test_rsa.key')) msg = key.sign_ssh_data(b'ice weasels') self.assertTrue(type(msg) is Message) msg.rewind() self.assertEqual('ssh-rsa', msg.get_text()) sig = bytes().join([byte_chr(int(x, 16)) for x in SIGNED_RSA.split(':')]) self.assertEqual(sig, msg.get_binary()) msg.rewind() pub = RSAKey(data=key.asbytes()) self.assertTrue(pub.verify_ssh_sig(b'ice weasels', msg))
def test_handle_13_failure(self): # Test handling a SSH2_AGENTC_SIGN_REQUEST (where no identity) msg = Message() msg.add_byte(byte_chr(13)) # The id of the key to sign with - in this case it doesn't exist key = b'\x0e' * 10 msg.add_int(len(key)) msg.add_bytes(bytes(key)) # A blob of binary to sign blob = b'\x0e' * 10 msg.add_int(len(blob)) msg.add_bytes(blob) mtype, msg = self.send(msg) self.assertEqual(mtype, 5)
def _send_client_message(self, message_type): self.setup_test_server(connect_kwargs={}) self.ts._send_message = Mock() # NOTE: this isn't 100% realistic (most of these message types would # have actual other fields in 'em) but it suffices to test the level of # message dispatch we're interested in here. msg = Message() # TODO: really not liking the whole cMSG_XXX vs MSG_XXX duality right # now, esp since the former is almost always just byte_chr(the # latter)...but since that's the case... msg.add_byte(byte_chr(message_type)) self.tc._send_message(msg) # No good way to actually wait for server action (see above tests re: # MSG_UNIMPLEMENTED). Grump. time.sleep(0.1)
def _send_identities(self): msg = Message() kkmip_keys = self._kkmip.get_keys() # add response byte msg.add_byte(byte_chr(SSH_AGENT_IDENTITIES_ANSWER)) # add number of keys msg.add_int(len(kkmip_keys)) for key in kkmip_keys: for l in textwrap.wrap(key.get_openssh_pubkey_format(), width=58): logger.debug(l) # add key in PEM format msg.add_string(key.get_pem_bytes()) # add comment msg.add_string(key.get_comment()) self._send_reply(msg)
( _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
import os from hashlib import sha1 from paramiko.common import * from paramiko import util from paramiko.message import Message from paramiko.py3compat import byte_chr, long, 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 G = 2 b7fffffffffffffff = byte_chr(0x7f) + max_byte * 7 b0000000000000000 = zero_byte * 8 NAME = "gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g=="
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, paramiko.util.format_binary(out, 'OUT: ')) self._write_all(out)
from hashlib import sha1 import paramiko 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
import struct import sys import threading import time import tempfile import stat from select import select from paramiko.common import asbytes, io_sleep from paramiko.py3compat import byte_chr from paramiko.ssh_exception import SSHException, AuthenticationException from paramiko.message import Message from paramiko.pkey import PKey from paramiko.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.
MSG_SERVICE_ACCEPT = range(1, 7) 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) 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)
""" import os from hashlib import sha1, sha256 from paramiko import util from paramiko.common import DEBUG from paramiko.message import Message from paramiko.py3compat import byte_chr, byte_ord, byte_mask from paramiko.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
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)
import threading import time import tempfile import stat from select import select from paramiko.common import asbytes, io_sleep from paramiko.py3compat import byte_chr from paramiko.ssh_exception import SSHException, AuthenticationException from paramiko.message import Message from paramiko.pkey import PKey from paramiko.util import retry_on_signal SSH_AGENT_FAILURE = 5 SSH_AGENT_SUCCESS = 6 cSSH2_AGENTC_REQUEST_IDENTITIES = byte_chr(11) SSH2_AGENT_IDENTITIES_ANSWER = 12 cSSH2_AGENTC_SIGN_REQUEST = byte_chr(13) SSH2_AGENT_SIGN_RESPONSE = 14 cSSH_AGENTC_ADD_IDENTITY = byte_chr(17) cSSH_AGENTC_REMOVE_IDENTITY = byte_chr(18) cSSH_AGENTC_REMOVE_ALL_IDENTITIES = byte_chr(19) cSSH_AGENTC_ADD_ID_CONSTRAINED = byte_chr(25) cSSH_AGENTC_CONSTRAIN_LIFETIME = byte_chr(1) cSSH_AGENTC_CONSTRAIN_CONFIRM = byte_chr(2) class AgentSSH(object): def __init__(self): self._conn = None
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)
# pylint: disable=W0212 """ Class, functions and variables used to add pkcs11 devices to ssh-agent """ from paramiko.agent import Agent from paramiko.agent import Message from paramiko.py3compat import byte_chr # Pulled from OpenSSH's authfd.h file SSH_AGENT_FAILURE = 5 SSH_AGENT_SUCCESS = 6 SSH_AGENTC_ADD_SMARTCARD_KEY = byte_chr(20) SSH_AGENTC_REMOVE_SMARTCARD_KEY = byte_chr(21) # Ansi color codes OKAY = '\033[92m[ OKAY ]\033[0m' FAIL = '\033[91m[ FAIL ]\033[0m' def display_results(ret_val): """ Displays ANSI colored output to indicate success or failure """ result_output = OKAY if ret_val == SSH_AGENT_SUCCESS else FAIL print('\033[A\033[70G {}'.format(result_output)) class SmartCardSSH(): """ class for adding and removing pkcs11 devices to ssh agents """ def __init__(self, pkcs11_file='/usr/local/lib/opensc-pkcs11.so'): self._pkcs11_so = pkcs11_file def remove_key(self, show_results=True):
( 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
@staticmethod def from_local_shell(): username = os.getlogin() groups = [] for group in grp.getgrall(): if username in group.gr_mem: groups.append(group.gr_name) return JanusContext(username, groups, 'shell') def __str__(self): return "Janus Context - Username: {username}, Groups: {groups}, " \ "Request Source: {req_source}, Request Address: {req_addr}, " \ "Request UUID: {request_id}".format(**self.__dict__) SSH2_AGENTC_ADD_IDENTITY = byte_chr(17) SSH2_AGENTC_ADD_ID_CONSTRAINED = byte_chr(25) SSH_AGENT_CONSTRAIN_LIFETIME = byte_chr(1) SSH_AGENT_SUCCESS = 6 class JanusSSHAgent(agent.Agent): def __init__(self, sock_path): agent.AgentSSH.__init__(self) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(sock_path) self.sock = sock self.sock_path = sock_path self._connect(self.sock) def add_key_cert(self, key, cert): if not key.can_sign():
""" 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. """ from Crypto.Hash import SHA from paramiko import util from paramiko.common import max_byte, zero_byte from paramiko.message import Message from paramiko.py3compat import byte_chr, long, byte_mask from paramiko.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)] # draft-ietf-secsh-transport-09.txt, page 17 P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF G = 2 b7fffffffffffffff = byte_chr(0x7f) + max_byte * 7 b0000000000000000 = zero_byte * 8 class KexGroup1(object): name = 'diffie-hellman-group1-sha1' def __init__(self, transport): self.transport = transport
import os from hashlib import sha1 from paramiko.common import * from paramiko import util from paramiko.message import Message from paramiko.py3compat import byte_chr, long, 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://dl.ietf.org/html/rfc4462.html#section-2>`_ """ # draft-ietf-secsh-transport-09.txt, page 17 P = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF G = 2 b7fffffffffffffff = byte_chr(0x7f) + max_byte * 7 b0000000000000000 = zero_byte * 8
from paramiko.message import Message from paramiko.py3compat import byte_chr, long from paramiko.ssh_exception import SSHException from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat from cryptography.exceptions import UnsupportedAlgorithm from binascii import hexlify # x25519 was added in cryptography 2.0, but we support down to cryptography 1.5 try: from cryptography.hazmat.primitives.asymmetric import x25519 except ImportError: x25519 = None _MSG_KEXC25519_INIT, _MSG_KEXC25519_REPLY = range(30, 32) c_MSG_KEXC25519_INIT, c_MSG_KEXC25519_REPLY = [ byte_chr(c) for c in range(30, 32) ] class KexCurve25519(object): name = "*****@*****.**" hash_algo = sha256 K = None def __init__(self, transport): self.transport = transport self.P = long(0) # Client public key self.Q_C = None # Server public key
class ECDSAKey(PKey): """ Representation of an ECDSA key which can be used to sign and verify SSH2 data. """ def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None, validate_point=True): self.verifying_key = None self.signing_key = None if file_obj is not None: self._from_private_key(file_obj, password) return if filename is not None: self._from_private_key_file(filename, password) return if (msg is None) and (data is not None): msg = Message(data) if vals is not None: self.signing_key, self.verifying_key = vals else: if msg is None: raise SSHException('Key object may not be empty') if msg.get_text() != 'ecdsa-sha2-nistp256': raise SSHException('Invalid key') curvename = msg.get_text() if curvename != 'nistp256': raise SSHException("Can't handle curve of type %s" % curvename) pointinfo = msg.get_binary() if pointinfo[0:1] != four_byte: raise SSHException('Point compression is being used: %s' % binascii.hexlify(pointinfo)) self.verifying_key = VerifyingKey.from_string( pointinfo[1:], curve=curves.NIST256p, validate_point=validate_point) self.size = 256 def asbytes(self): key = self.verifying_key m = Message() m.add_string('ecdsa-sha2-nistp256') m.add_string('nistp256') point_str = four_byte + key.to_string() m.add_string(point_str) return m.asbytes() def __str__(self): return self.asbytes() def __hash__(self): h = hash(self.get_name()) h = h * 37 + hash(self.verifying_key.pubkey.point.x()) h = h * 37 + hash(self.verifying_key.pubkey.point.y()) return hash(h) def get_name(self): return 'ecdsa-sha2-nistp256' def get_bits(self): return self.size def can_sign(self): return self.signing_key is not None def sign_ssh_data(self, data): sig = self.signing_key.sign_deterministic(data, sigencode=self._sigencode, hashfunc=sha256) m = Message() m.add_string('ecdsa-sha2-nistp256') m.add_string(sig) return m def verify_ssh_sig(self, data, msg): if msg.get_text() != 'ecdsa-sha2-nistp256': return False sig = msg.get_binary() # verify the signature by SHA'ing the data and encrypting it # using the public key. hash_obj = sha256(data).digest() return self.verifying_key.verify_digest(sig, hash_obj, sigdecode=self._sigdecode) def write_private_key_file(self, filename, password=None): key = self.signing_key or self.verifying_key self._write_private_key_file('EC', filename, key.to_der(), password) def write_private_key(self, file_obj, password=None): key = self.signing_key or self.verifying_key self._write_private_key('EC', file_obj, key.to_der(), password) @staticmethod def generate(curve=curves.NIST256p, progress_func=None): """ Generate a new private ECDSA key. This factory function can be used to generate a new host key or authentication key. :param function progress_func: Not used for this type of key. :returns: A new private key (`.ECDSAKey`) object """ signing_key = SigningKey.generate(curve) key = ECDSAKey(vals=(signing_key, signing_key.get_verifying_key())) return key ### internals... def _from_private_key_file(self, filename, password): data = self._read_private_key_file('EC', filename, password) self._decode_key(data) def _from_private_key(self, file_obj, password): data = self._read_private_key('EC', file_obj, password) self._decode_key(data) ALLOWED_PADDINGS = [ one_byte, byte_chr(2) * 2, byte_chr(3) * 3, byte_chr(4) * 4, byte_chr(5) * 5, byte_chr(6) * 6, byte_chr(7) * 7 ] def _decode_key(self, data): s, padding = der.remove_sequence(data) if padding: if padding not in self.ALLOWED_PADDINGS: raise ValueError("weird padding: %s" % u(binascii.hexlify(data))) data = data[:-len(padding)] key = SigningKey.from_der(data) self.signing_key = key self.verifying_key = key.get_verifying_key() self.size = 256 def _sigencode(self, r, s, order): msg = Message() msg.add_mpint(r) msg.add_mpint(s) return msg.asbytes() def _sigdecode(self, sig, order): msg = Message(sig) r = msg.get_mpint() s = msg.get_mpint() return r, s
""" 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 paramiko import util from paramiko.common import max_byte, zero_byte from paramiko.message import Message from paramiko.py3compat import byte_chr, long, byte_mask from paramiko.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):
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
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)
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.transport.gss_kex_used = True 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) raise SSHException('GSS KexGroup1 asked to handle packet type %d' % 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 = paramiko.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) self.transport._set_K_H(K, sha1(str(hm)).digest()) 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, self.transport.session_id) else: self.kexgss.ssh_check_mic(mic_token, self.transport.session_id) 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._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:\nMajor Status: %s\nMinor Status: %s\ \nError Message: %s\n") % (str(maj_status), str(min_status), err_msg)
""" Ephemeral Elliptic Curve Diffie-Hellman (ECDH) key exchange RFC 5656, Section 4 """ from hashlib import sha256, sha384, sha512 from paramiko.message import Message from paramiko.py3compat import byte_chr, long from paramiko.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):
import struct import sys import threading import time import tempfile import stat from select import select from paramiko.common import asbytes, io_sleep from paramiko.py3compat import byte_chr from paramiko.ssh_exception import SSHException from paramiko.message import Message from paramiko.pkey import PKey from paramiko.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
def send_window_adjust(self, consumed): m = Message() m.add_byte(byte_chr(SSH2_MSG_CHANNEL_WINDOW_ADJUST)) m.add_int(self.channel.remote_chanid) m.add_int(consumed) self.channel.transport._send_user_message(m)