def test_C_generate_ecdsa(self): key = ECDSAKey.generate() msg = key.sign_ssh_data(b'jerri blank') msg.rewind() self.assertTrue(key.verify_ssh_sig(b'jerri blank', msg)) self.assertEqual(key.get_bits(), 256) self.assertEqual(key.get_name(), 'ecdsa-sha2-nistp256') key = ECDSAKey.generate(bits=256) msg = key.sign_ssh_data(b'jerri blank') msg.rewind() self.assertTrue(key.verify_ssh_sig(b'jerri blank', msg)) self.assertEqual(key.get_bits(), 256) self.assertEqual(key.get_name(), 'ecdsa-sha2-nistp256') key = ECDSAKey.generate(bits=384) msg = key.sign_ssh_data(b'jerri blank') msg.rewind() self.assertTrue(key.verify_ssh_sig(b'jerri blank', msg)) self.assertEqual(key.get_bits(), 384) self.assertEqual(key.get_name(), 'ecdsa-sha2-nistp384') key = ECDSAKey.generate(bits=521) msg = key.sign_ssh_data(b'jerri blank') msg.rewind() self.assertTrue(key.verify_ssh_sig(b'jerri blank', msg)) self.assertEqual(key.get_bits(), 521) self.assertEqual(key.get_name(), 'ecdsa-sha2-nistp521')
def test_16_compare_ecdsa_384(self): # verify that the private & public keys compare equal key = ECDSAKey.from_private_key_file(_support("test_ecdsa_384.key")) self.assertEqual(key, key) pub = ECDSAKey(data=key.asbytes()) self.assertTrue(key.can_sign()) self.assertTrue(not pub.can_sign()) self.assertEqual(key, pub)
def test_20_compare_ecdsa_521(self): # verify that the private & public keys compare equal key = ECDSAKey.from_private_key_file(test_path('test_ecdsa_521.key')) self.assertEqual(key, key) pub = ECDSAKey(data=key.asbytes()) self.assertTrue(key.can_sign()) self.assertTrue(not pub.can_sign()) self.assertEqual(key, pub)
def test_12_compare_ecdsa(self): # verify that the private & public keys compare equal key = ECDSAKey.from_private_key_file('tests/test_ecdsa.key') self.assertEquals(key, key) pub = ECDSAKey(data=bytes(key)) self.assert_(key.can_sign()) self.assert_(not pub.can_sign()) self.assertEquals(key, pub)
def test_10_load_ecdsa(self): key = ECDSAKey.from_private_key_file('tests/test_ecdsa.key') self.assertEquals(b'ecdsa-sha2-nistp256', key.get_name()) exp_ecdsa = FINGER_ECDSA.split()[1].replace(b':', b'') my_ecdsa = hexlify(key.get_fingerprint()) self.assertEquals(exp_ecdsa, my_ecdsa) self.assertEquals(PUB_ECDSA.split()[1], key.get_base64()) self.assertEquals(256, key.get_bits()) s = BytesIO() key.write_private_key(s) self.assertEquals(ECDSA_PRIVATE_OUT, s.getvalue()) s.seek(0) key2 = ECDSAKey.from_private_key(StringIO(s.getvalue().decode())) self.assertEquals(key, key2)
def test_21_sign_ecdsa_521(self): # verify that the rsa private key can sign and verify key = ECDSAKey.from_private_key_file(test_path('test_ecdsa_521.key')) msg = key.sign_ssh_data(b'ice weasels') self.assertTrue(type(msg) is Message) msg.rewind() self.assertEqual('ecdsa-sha2-nistp521', msg.get_text()) # ECDSA signatures, like DSS signatures, tend to be different # each time, so we can't compare against a "known correct" # signature. # Even the length of the signature can change. msg.rewind() pub = ECDSAKey(data=key.asbytes()) self.assertTrue(pub.verify_ssh_sig(b'ice weasels', msg))
def test_14_load_ecdsa_384(self): key = ECDSAKey.from_private_key_file(test_path('test_ecdsa_384.key')) self.assertEqual('ecdsa-sha2-nistp384', key.get_name()) exp_ecdsa = b(FINGER_ECDSA_384.split()[1].replace(':', '')) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA_384.split()[1], key.get_base64()) self.assertEqual(384, key.get_bits()) s = StringIO() key.write_private_key(s) self.assertEqual(ECDSA_PRIVATE_OUT_384, s.getvalue()) s.seek(0) key2 = ECDSAKey.from_private_key(s) self.assertEqual(key, key2)
def test_13_sign_ecdsa(self): # verify that the rsa private key can sign and verify key = ECDSAKey.from_private_key_file('tests/test_ecdsa.key') msg = key.sign_ssh_data(rng, b'ice weasels') self.assert_(type(msg) is Message) msg.rewind() self.assertEquals(b'ecdsa-sha2-nistp256', msg.get_string()) # ECDSA signatures, like DSS signatures, tend to be different # each time, so we can't compare against a "known correct" # signature. # Even the length of the signature can change. msg.rewind() pub = ECDSAKey(data=bytes(key)) self.assert_(pub.verify_ssh_sig(b'ice weasels', msg))
def test_10_load_ecdsa_256(self): key = ECDSAKey.from_private_key_file(_support("test_ecdsa_256.key")) self.assertEqual("ecdsa-sha2-nistp256", key.get_name()) exp_ecdsa = b(FINGER_ECDSA_256.split()[1].replace(":", "")) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA_256.split()[1], key.get_base64()) self.assertEqual(256, key.get_bits()) s = StringIO() key.write_private_key(s) self.assertEqual(ECDSA_PRIVATE_OUT_256, s.getvalue()) s.seek(0) key2 = ECDSAKey.from_private_key(s) self.assertEqual(key, key2)
def test_11_load_ecdsa_password(self): key = ECDSAKey.from_private_key_file('tests/test_ecdsa_password.key', 'television') self.assertEquals(b'ecdsa-sha2-nistp256', key.get_name()) exp_ecdsa = FINGER_ECDSA.split()[1].replace(b':', b'') my_ecdsa = hexlify(key.get_fingerprint()) self.assertEquals(exp_ecdsa, my_ecdsa) self.assertEquals(PUB_ECDSA.split()[1], key.get_base64()) self.assertEquals(256, key.get_bits())
def test_15_load_ecdsa_password_384(self): key = ECDSAKey.from_private_key_file(_support('test_ecdsa_password_384.key'), b'television') self.assertEqual('ecdsa-sha2-nistp384', key.get_name()) exp_ecdsa = b(FINGER_ECDSA_384.split()[1].replace(':', '')) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA_384.split()[1], key.get_base64()) self.assertEqual(384, key.get_bits())
def test_19_load_ecdsa_password_521(self): key = ECDSAKey.from_private_key_file(test_path('test_ecdsa_password_521.key'), b'television') self.assertEqual('ecdsa-sha2-nistp521', key.get_name()) exp_ecdsa = b(FINGER_ECDSA_521.split()[1].replace(':', '')) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA_521.split()[1], key.get_base64()) self.assertEqual(521, key.get_bits())
def test_11_load_ecdsa_password(self): key = ECDSAKey.from_private_key_file(test_path("test_ecdsa_password.key"), b"television") self.assertEqual("ecdsa-sha2-nistp256", key.get_name()) exp_ecdsa = b(FINGER_ECDSA.split()[1].replace(":", "")) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA.split()[1], key.get_base64()) self.assertEqual(256, key.get_bits())
def test_load_EC_key_new_format(self): key = ECDSAKey.from_private_key_file(_support('test_ecdsa_384_o.key'), b'television') self.assertEqual('ecdsa-sha2-nistp384', key.get_name()) self.assertEqual(PUB_EC_384_OPENSSH.split()[1], key.get_base64()) self.assertEqual(384, key.get_bits()) exp_fp = b(FINGER_EC_384_OPENSSH.split()[1].replace(':', '')) my_fp = hexlify(key.get_fingerprint()) self.assertEqual(exp_fp, my_fp)
def test_load_ecdsa_password_521(self): key = ECDSAKey.from_private_key_file( _support('test_ecdsa_password_521.key'), b'television') self.assertEqual('ecdsa-sha2-nistp521', key.get_name()) exp_ecdsa = b(FINGER_ECDSA_521.split()[1].replace(':', '')) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA_521.split()[1], key.get_base64()) self.assertEqual(521, key.get_bits())
def test_load_ecdsa_521(self): key = ECDSAKey.from_private_key_file(_support('test_ecdsa_521.key')) self.assertEqual('ecdsa-sha2-nistp521', key.get_name()) exp_ecdsa = b(FINGER_ECDSA_521.split()[1].replace(':', '')) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA_521.split()[1], key.get_base64()) self.assertEqual(521, key.get_bits()) s = StringIO() key.write_private_key(s) # Different versions of OpenSSL (SSLeay versions 0x1000100f and # 0x1000207f for instance) use different apparently valid (as far as # ssh-keygen is concerned) padding. So we can't check the actual value # of the pem encoded key. s.seek(0) key2 = ECDSAKey.from_private_key(s) self.assertEqual(key, key2)
def test_11_load_ecdsa_password(self): key = ECDSAKey.from_private_key_file( test_path('test_ecdsa_password.key'), b'television') self.assertEqual('ecdsa-sha2-nistp256', key.get_name()) exp_ecdsa = b(FINGER_ECDSA.split()[1].replace(':', '')) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA.split()[1], key.get_base64()) self.assertEqual(256, key.get_bits())
def test_18_load_ecdsa_521(self): key = ECDSAKey.from_private_key_file(test_path('test_ecdsa_521.key')) self.assertEqual('ecdsa-sha2-nistp521', key.get_name()) exp_ecdsa = b(FINGER_ECDSA_521.split()[1].replace(':', '')) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA_521.split()[1], key.get_base64()) self.assertEqual(521, key.get_bits()) s = StringIO() key.write_private_key(s) # Different versions of OpenSSL (SSLeay versions 0x1000100f and # 0x1000207f for instance) use different apparently valid (as far as # ssh-keygen is concerned) padding. So we can't check the actual value # of the pem encoded key. s.seek(0) key2 = ECDSAKey.from_private_key(s) self.assertEqual(key, key2)
def test_15_load_ecdsa_password_384(self): key = ECDSAKey.from_private_key_file( _support("test_ecdsa_password_384.key"), b"television" ) self.assertEqual("ecdsa-sha2-nistp384", key.get_name()) exp_ecdsa = b(FINGER_ECDSA_384.split()[1].replace(":", "")) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA_384.split()[1], key.get_base64()) self.assertEqual(384, key.get_bits())
def test_19_load_ecdsa_password_521(self): key = ECDSAKey.from_private_key_file( _support("test_ecdsa_password_521.key"), b"television" ) self.assertEqual("ecdsa-sha2-nistp521", key.get_name()) exp_ecdsa = b(FINGER_ECDSA_521.split()[1].replace(":", "")) my_ecdsa = hexlify(key.get_fingerprint()) self.assertEqual(exp_ecdsa, my_ecdsa) self.assertEqual(PUB_ECDSA_521.split()[1], key.get_base64()) self.assertEqual(521, key.get_bits())
def dehydrate(self, bundle): if bundle.obj.key_type == "ssh-rsa": key = RSAKey(data=base64.b64decode(bundle.obj.public_key)) elif bundle.obj.key_type == "ssh-dss": key = DSSKey(data=base64.b64decode(bundle.obj.public_key)) elif bundle.obj.key_type.startswith("ecdsa"): key = ECDSAKey(data=base64.b64decode(bundle.obj.public_key)) else: raise HydrationError("Unknown key type: %s" % bundle.object.key_type) bundle.data['fingerprint'] = u(hexlify(key.get_fingerprint())) return bundle
def load(self): """Try to load the public key We support RSA, ECDSA and Ed25519 keys and return instances of: * paramiko.rsakey.RSAKey * paramiko.ecdsakey.ECDSAKey * paramiko.ed25519key.Ed25519Key (requires paramiko >= 2.2) """ # I don't think there is a key type independent way of doing this public_key_blob = b64decode(self.key_base64) if self.key_algorithm.startswith('ssh-ed25519'): try: return Ed25519Key(data=public_key_blob) except NameError: raise ValidationError('Paramiko too old to load ed25519 keys') elif self.key_algorithm.startswith('ecdsa-'): return ECDSAKey(data=public_key_blob) elif self.key_algorithm.startswith('ssh-rsa'): return RSAKey(data=public_key_blob) raise SSHException('Key is not RSA, ECDSA or Ed25519')
def clean(self): data = super().clean() key_type = data.get('key_type') public_key = data.get('public_key') try: if key_type == "ssh-rsa": k = RSAKey(data=base64.b64decode(public_key)) elif key_type == "ssh-dss": k = DSSKey(data=base64.b64decode(public_key)) elif key_type.startswith('ecdsa'): k = ECDSAKey(data=base64.b64decode(public_key)) else: raise forms.ValidationError( _("Unsupport key type: %(keytype)s"), code='invalid keytype', params={'key_type': key_type} ) data['key_type'] = k.get_name() data['public_key'] = k.get_base64() except (TypeError, SSHException, UnicodeDecodeError) as err: if len(public_key) > 30: body = public_key[0:30] else: body = public_key raise forms.ValidationError( _("Body of SSH public key is invalid:\n%(body)s\n" "Error: %(err)s"), code='invalid key body', params={'body': body + "...", 'err': err} ) return data
def test_load_openssh_format_EC_key(self): key = ECDSAKey.from_private_key_file( _support("test_ecdsa_384_openssh.key"), b"television") self.assertEqual("ecdsa-sha2-nistp384", key.get_name()) self.assert_key_fingerprints(key, FINGER_EC_384_OPENSSH)
class SSH(AbstractCommunicator): CONFIGURATION_KEYS = ("host_key", "host_key_type", "username", "private_key", "private_key_type") SUPPORTED_HOST_TYPES = ("Darwin", "Linux_AMD64", "Windows") IDENTIFIER = "SSH" PRIVATE_KEY_FORMAT_MAPPINGS = { 'DSS': paramiko.DSSKey.from_private_key, 'RSA': paramiko.RSAKey.from_private_key, 'ECDSA': paramiko.ECDSAKey.from_private_key, 'Ed25519': paramiko.Ed25519Key.from_private_key } HOST_KEY_FORMAT_MAPPINGS = { 'ssh-dss': paramiko.DSSKey, 'ssh-rsa': paramiko.RSAKey, 'ssh-ed25519': paramiko.Ed25519Key } for key in ECDSAKey.supported_key_format_identifiers(): HOST_KEY_FORMAT_MAPPINGS[key] = paramiko.ECDSAKey def __init__(self, host): super().__init__(host) self.username = self.config["username"] def get_host_key(self) -> PKey: # Decide what kind of key we're looking at and create an object # to hold it accordingly. key_type = self.host.config['host_key_type'] if key_type not in self.HOST_KEY_FORMAT_MAPPINGS: raise SSHError(f"Unable to handle key of type {key_type}") try: key = self.host.config['host_key'].encode('utf-8') host_key = self.HOST_KEY_FORMAT_MAPPINGS[key_type]( data=decodebytes(key)) except binascii.Error as e: raise InvalidHostKey(repr(self.host), e) return host_key def get_private_key(self): # Decide what kind of key we're looking at and create an object # to hold it accordingly. key_type = self.config['private_key_type'] if key_type not in self.PRIVATE_KEY_FORMAT_MAPPINGS: raise SSHError(f"Unable to handle key of type {key_type}") try: key = self.config['private_key'] private_key = self.PRIVATE_KEY_FORMAT_MAPPINGS[key_type]( StringIO(key)) except binascii.Error as e: raise SSHError(f"Private key error {repr(self.host)}", e) return private_key def get_client(self): client = paramiko.SSHClient() host_keys = HostKeys() host_keys.add(hostname=self.host.address, keytype=self.config['host_key_type'], key=self.get_host_key()) client._host_keys = host_keys # If you not a better way than accessing a private member I am all ears return client def execute_command(self, command: str) -> CommandResponse: client = self.get_client() try: client.connect(self.host.address, username=self.config["username"], pkey=self.get_private_key(), timeout=settings.SSH_CONNECT_TIMEOUT) stdin, stdout, stderr = client.exec_command( command=command, timeout=settings.SSH_EXEC_TIMEOUT) return_code = stdout.channel.recv_exit_status() stdout_str = stdout.read().decode('UTF-8') stderr_str = stderr.read().decode('UTF-8') if return_code != 0: logger.info( f"host={self.username}@{self.host.address} rc={return_code} command={command} stdout={stdout_str} stderr={stderr_str}" ) except paramiko.SSHException as e: logger.exception( f"Error: host={self.username}@{self.host.address}, command={command}" ) raise SSHError( f"Ran into problems connecting to {self.username}@{self.host.address}: {e}" ) finally: client.close() return CommandResponse(return_code, stdout_str, stderr_str) def is_host_reachable(self) -> bool: try: if self.host.type == "Windows": response = self.execute_command('date /t') else: response = self.execute_command('true') except Exception: return False return True
args = parser.parse_args() args.local_dir = os.path.abspath(args.local_dir) logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(message)s", datefmt="%H:%M:%S") logging.getLogger("paramiko.transport").setLevel(logging.ERROR) logger = logging.getLogger() if args.configure: logger.info("here is where we run ansible playbooks") exit(0) try: key_file = os.path.expanduser(args.identity) private_key = ECDSAKey.from_private_key_file(key_file) except FileNotFoundError as e: logger.error(f"{args.identity} not found") exit(1) except SSHException as e: logger.error(f"{key_file}; {e}") exit(1) ssh = SSHClient() ssh.set_missing_host_key_policy(AutoAddPolicy()) ssh.load_system_host_keys() try: logger.info(f"connecting to {args.hostname}") ssh.connect(args.hostname, username=args.user, pkey=private_key) except AuthenticationException as e:
from ...command_util import GenericUserError from .. import URLConfig from ..archive import ensure_archive from . import Uploader KEYTYPES = { 'RSA': RSAKey, 'ECDSA': ECDSAKey, 'DSA': DSSKey, 'DSS': DSSKey, 'ED25519': Ed25519Key } KNOWN_HOSTS_KEY_TYPE_MAP = { 'RSA': ('ssh-rsa', ), 'ECDSA': tuple(ECDSAKey.supported_key_format_identifiers()), 'DSA': ('ssh-dss', ), 'DSS': ('ssh-dss', ), 'ED25519': ('ssh-ed25519', ) } class DumbSFTPUploader(Uploader): ''' A dumb SFTP uploader that just sends a bundle to a remote directory. The server has to decide what to do with the bundle (e.g., putting it where it can be downloaded) ''' def __init__(self, upload_url): '''
def test_load_ecdsa_password_521(self): key = ECDSAKey.from_private_key_file( _support('test_ecdsa_password_521.key'), b'television') self.assert_key_values(key, 'ecdsa-sha2-nistp521', 521, PUB_ECDSA_521, FINGER_ECDSA_521.split()[1], FINGER_SHA256_ECDSA_521)