def _get_fingerprint(self, signing_key): ssh_key = SSHKey("ssh-ed25519 {0}" .format(signing_key.get_base64())) try: ssh_key.parse() except: self._raise_error("INVALID signing key type. ABORTING.") return ssh_key.hash_sha256() # SHA256:xyz
def check_key(self, pubkey, bits, fingerprint_md5, fingerprint_sha256, options, comment, **kwargs): # pylint:disable=too-many-arguments """ Checks valid key """ ssh = SSHKey(pubkey, **kwargs) ssh.parse() self.assertEqual(ssh.bits, bits) self.assertEqual(ssh.hash_md5(), fingerprint_md5) self.assertEqual(ssh.options_raw, options) self.assertEqual(ssh.comment, comment) if fingerprint_sha256 is not None: self.assertEqual(ssh.hash_sha256(), fingerprint_sha256)
def key_to_public_key(key): # type: (str) -> PublicKey """Convert the string representation of a public key to a PublicKey transfer object.""" pubkey = SSHKey(key, strict=True) pubkey.parse() return PublicKey( public_key=pubkey.keydata.strip(), fingerprint=pubkey.hash_md5().replace("MD5:", ""), fingerprint_sha256=pubkey.hash_sha256().replace("SHA256:", ""), )
def sshkey_good_format(key): """Return False if the key hasn't a known format, else return a hash""" sshkey = SSHKey(key, strict = True) try: sshkey.parse() except: return False # We remove the "SHA256:" header and we add "=" at the end return sshkey.hash_sha256()[7:] + "="
def parse_key(data): key = {} ssh_key = SSHKey(data.decode()) if ssh_key.bits is not None: name = ssh_key.key_type.decode() key[name + ":size"] = ssh_key.bits key[name + ":sha256"] = ssh_key.hash_sha256() return key
def hash(sshkey): """ Return hash of sshkey """ key = SSHKey(sshkey, strict=True) try: key.parse() except: app.logger.error("ERROR: wrong sshkey format: " + sshkey, file=sys.stderr) return ("Wrong ssh key format - " + str(uuid.uuid4())) # We remove the "SHA256:" header and we add "=" at the end return key.hash_sha256()[7:] + "="
def check_auth_publickey(self, username, key): ssh_pub_key = SSHKey("{} {}".format(key.get_name(), key.get_base64())) ssh_pub_key.parse() logging.info("check_auth_publickey: username=%s, key=%s %s %sbits", username, key.get_name(), ssh_pub_key.hash_sha256(), ssh_pub_key.bits) if self.args.disable_pubkey_auth: logging.debug( "Publickey login attempt, but publickey auth was disabled!") return paramiko.AUTH_FAILED return self.session.authenticator.authenticate(username, key=key)
def parse(self): """ Cleans the key from comments and options and pulates the MD5, SHA256 and SHA512 sums. """ ssh_key = SSHKey(self.public_key, parse_options=False, strict_mode=True) ssh_key.parse() # Tiny hack, to get the clean key self.public_key = ' '.join(ssh_key._split_key(ssh_key.keydata)) self.md5 = ssh_key.hash_md5() self.sha256 = ssh_key.hash_sha256() self.sha512 = ssh_key.hash_sha512()
def _get_fingerprint(self, signing_key): # This is hard-coded for now, until we figure out # a way to do this properly: encoding = self._add_encoding(b'ssh-ed25519') +\ self._add_encoding(signing_key) ssh_key_text: str = base64.b64encode(encoding).decode("utf-8") ssh_key = SSHKey("ssh-ed25519 {0}".format(ssh_key_text)) try: ssh_key.parse() except Exception: self._raise_error("INVALID signing key type. ABORTING.") return ssh_key.hash_sha256() # SHA256:xyz
def add_public_key_to_user(self, key, user): # type: (str, str) -> None sql_user = User.get(self.session, name=user) assert sql_user public_key = SSHKey(key, strict=True) public_key.parse() sql_public_key = PublicKey( user_id=sql_user.id, public_key=public_key.keydata.strip(), fingerprint=public_key.hash_md5().replace("MD5:", ""), fingerprint_sha256=public_key.hash_sha256().replace("SHA256:", ""), key_size=public_key.bits, key_type=public_key.key_type, comment=public_key.comment, ) sql_public_key.add(self.session)
def auth_publickey(self, username, host, port, key): if key.can_sign(): ssh_pub_key = SSHKey("{} {}".format(key.get_name(), key.get_base64())) ssh_pub_key.parse() logging.info( "AuthenticatorPassThrough.auth_publickey: username=%s, key=%s %s %sbits", username, key.get_name(), ssh_pub_key.hash_sha256(), ssh_pub_key.bits) return self.connect(username, host, port, AuthenticationMethod.publickey, key=key) if self.REQUEST_AGENT: # Ein Publickey wird nur direkt von check_auth_publickey # übergeben. In dem Fall müssen wir den Client authentifizieren, # damit wir auf den Agent warten können! logging.debug( "authentication failed. accept connection and wait for agent.") return paramiko.AUTH_SUCCESSFUL return paramiko.AUTH_FAILED
def check_auth_publickey(self, username: Text, key: PKey) -> int: ssh_pub_key = SSHKey(f"{key.get_name()} {key.get_base64()}") ssh_pub_key.parse() logging.debug("check_auth_publickey: username=%s, key=%s %s %sbits", username, key.get_name(), ssh_pub_key.hash_sha256(), ssh_pub_key.bits) if self.session.session_log_dir: os.makedirs(self.session.session_log_dir, exist_ok=True) pubkeyfile_path = os.path.join(self.session.session_log_dir, 'publickeys') with open(pubkeyfile_path, 'a+') as pubkeyfile: pubkeyfile.write( f"{key.get_name()} {key.get_base64()} saved-from-auth-publickey\n" ) if self.args.disable_pubkey_auth: logging.debug( "Publickey login attempt, but publickey auth was disabled!") return paramiko.common.AUTH_FAILED if self.args.accept_first_publickey: logging.debug('host probing disabled - first key accepted') if self.args.disallow_publickey_auth: logging.debug( 'ignoring argument --disallow-publickey-auth, first key still accepted' ) self.session.authenticator.authenticate(username, key=None) self.session.accepted_key = key return paramiko.common.AUTH_SUCCESSFUL auth_result: int = self.session.authenticator.authenticate(username, key=key) if auth_result == paramiko.common.AUTH_SUCCESSFUL: self.session.accepted_key = key if self.session.accepted_key is not None and self.args.enable_trivial_auth: logging.debug("found valid key for trivial authentication") return paramiko.common.AUTH_FAILED if self.args.disallow_publickey_auth: return paramiko.common.AUTH_FAILED return auth_result
def auth_publickey(self, username: Text, host: Text, port: int, key: PKey) -> int: ssh_pub_key = SSHKey(f"{key.get_name()} {key.get_base64()}") ssh_pub_key.parse() if key.can_sign(): logging.debug( "AuthenticatorPassThrough.auth_publickey: username=%s, key=%s %s %sbits", username, key.get_name(), ssh_pub_key.hash_sha256(), ssh_pub_key.bits) return self.connect(username, host, port, AuthenticationMethod.publickey, key=key) # Ein Publickey wird nur direkt von check_auth_publickey # übergeben. In dem Fall müssen wir den Client authentifizieren, # damit wir auf den Agent warten können! publickey = paramiko.pkey.PublicBlob(key.get_name(), key.asbytes()) if probe_host(host, port, username, publickey): logging.debug( f"Found valid key for host {host}:{port} username={username}, key={key.get_name()} {ssh_pub_key.hash_sha256()} {ssh_pub_key.bits}bits" ) return paramiko.common.AUTH_SUCCESSFUL return paramiko.common.AUTH_FAILED
def connect(self) -> bool: message = None self.transport = paramiko.Transport((self.host, self.port)) if self.CIPHERS: if not isinstance(self.CIPHERS, tuple): raise ValueError('client ciphers must be a tuple') self.transport.get_security_options().ciphers = self.CIPHERS try: if self.method is AuthenticationMethod.password: self.transport.connect(username=self.user, password=self.password) elif self.method is AuthenticationMethod.publickey: self.transport.connect(username=self.user, password=self.password, pkey=self.key) elif self.method is AuthenticationMethod.agent: if self.agent is not None: keys = self.agent.get_keys() if not keys: raise NoAgentKeys() for k in keys: try: self.transport.connect(username=self.user, password=self.password, pkey=k) ssh_pub_key = SSHKey( f"{k.get_name()} {k.get_base64()}") ssh_pub_key.parse() logging.debug( "ssh-mitm connected to remote host with username=%s, key=%s %s %sbits", self.user, k.get_name(), ssh_pub_key.hash_sha256(), ssh_pub_key.bits) break except paramiko.AuthenticationException: self.transport.close() self.transport = paramiko.Transport( (self.host, self.port)) else: logging.error('authentication method "%s" not supported!', self.method.value) return False remotekey = self.transport.get_remote_server_key() if not self.check_host_key(f"{self.host}:{self.port}", remotekey.get_name(), remotekey): raise InvalidHostKey() self.connected = True return True except paramiko.SSHException: message = "general ssh error" except NoAgentKeys: message = "no agent keys found" except InvalidHostKey: message = "Hostkey is invalid" userstring = f"{self.user}:{self.password}@{self.host}:{self.port}" logging.debug('Authentication failed: %s, User: %s, Message: %s', self.method.value, userstring, message or "") return False