Host key docs (order + tweaks)
This commit is contained in:
parent
1556853713
commit
4bcac18d17
|
@ -16,9 +16,6 @@
|
|||
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
"""
|
||||
`.HostKeys`
|
||||
"""
|
||||
|
||||
import base64
|
||||
import binascii
|
||||
|
@ -31,95 +28,21 @@ from paramiko.rsakey import RSAKey
|
|||
from paramiko.util import get_logger, constant_time_bytes_eq
|
||||
|
||||
|
||||
class InvalidHostKey(Exception):
|
||||
|
||||
def __init__(self, line, exc):
|
||||
self.line = line
|
||||
self.exc = exc
|
||||
self.args = (line, exc)
|
||||
|
||||
|
||||
class HostKeyEntry:
|
||||
"""
|
||||
Representation of a line in an OpenSSH-style "known hosts" file.
|
||||
"""
|
||||
|
||||
def __init__(self, hostnames=None, key=None):
|
||||
self.valid = (hostnames is not None) and (key is not None)
|
||||
self.hostnames = hostnames
|
||||
self.key = key
|
||||
|
||||
def from_line(cls, line, lineno=None):
|
||||
"""
|
||||
Parses the given line of text to find the names for the host,
|
||||
the type of key, and the key data. The line is expected to be in the
|
||||
format used by the openssh known_hosts file.
|
||||
|
||||
Lines are expected to not have leading or trailing whitespace.
|
||||
We don't bother to check for comments or empty lines. All of
|
||||
that should be taken care of before sending the line to us.
|
||||
|
||||
:param line: a line from an OpenSSH known_hosts file
|
||||
:type line: str
|
||||
"""
|
||||
log = get_logger('paramiko.hostkeys')
|
||||
fields = line.split(' ')
|
||||
if len(fields) < 3:
|
||||
# Bad number of fields
|
||||
log.info("Not enough fields found in known_hosts in line %s (%r)" %
|
||||
(lineno, line))
|
||||
return None
|
||||
fields = fields[:3]
|
||||
|
||||
names, keytype, key = fields
|
||||
names = names.split(',')
|
||||
|
||||
# Decide what kind of key we're looking at and create an object
|
||||
# to hold it accordingly.
|
||||
try:
|
||||
if keytype == 'ssh-rsa':
|
||||
key = RSAKey(data=base64.decodestring(key))
|
||||
elif keytype == 'ssh-dss':
|
||||
key = DSSKey(data=base64.decodestring(key))
|
||||
else:
|
||||
log.info("Unable to handle key of type %s" % (keytype,))
|
||||
return None
|
||||
except binascii.Error, e:
|
||||
raise InvalidHostKey(line, e)
|
||||
|
||||
return cls(names, key)
|
||||
from_line = classmethod(from_line)
|
||||
|
||||
def to_line(self):
|
||||
"""
|
||||
Returns a string in OpenSSH known_hosts file format, or None if
|
||||
the object is not in a valid state. A trailing newline is
|
||||
included.
|
||||
"""
|
||||
if self.valid:
|
||||
return '%s %s %s\n' % (','.join(self.hostnames), self.key.get_name(),
|
||||
self.key.get_base64())
|
||||
return None
|
||||
|
||||
def __repr__(self):
|
||||
return '<HostKeyEntry %r: %r>' % (self.hostnames, self.key)
|
||||
|
||||
|
||||
class HostKeys (UserDict.DictMixin):
|
||||
"""
|
||||
Representation of an openssh-style "known hosts" file. Host keys can be
|
||||
Representation of an OpenSSH-style "known hosts" file. Host keys can be
|
||||
read from one or more files, and then individual hosts can be looked up to
|
||||
verify server keys during SSH negotiation.
|
||||
|
||||
A HostKeys object can be treated like a dict; any dict lookup is equivalent
|
||||
to calling `lookup`.
|
||||
A `.HostKeys` object can be treated like a dict; any dict lookup is
|
||||
equivalent to calling `lookup`.
|
||||
|
||||
.. versionadded:: 1.5.3
|
||||
"""
|
||||
|
||||
def __init__(self, filename=None):
|
||||
"""
|
||||
Create a new HostKeys object, optionally loading keys from an openssh
|
||||
Create a new HostKeys object, optionally loading keys from an OpenSSH
|
||||
style host-key file.
|
||||
|
||||
:param filename: filename to load host keys from, or ``None``
|
||||
|
@ -150,7 +73,7 @@ class HostKeys (UserDict.DictMixin):
|
|||
|
||||
def load(self, filename):
|
||||
"""
|
||||
Read a file of known SSH host keys, in the format used by openssh.
|
||||
Read a file of known SSH host keys, in the format used by OpenSSH.
|
||||
This type of file unfortunately doesn't exist on Windows, but on
|
||||
posix, it will usually be stored in
|
||||
``os.path.expanduser("~/.ssh/known_hosts")``.
|
||||
|
@ -181,7 +104,7 @@ class HostKeys (UserDict.DictMixin):
|
|||
|
||||
def save(self, filename):
|
||||
"""
|
||||
Save host keys into a file, in the format used by openssh. The order of
|
||||
Save host keys into a file, in the format used by OpenSSH. The order of
|
||||
keys in the file will be preserved when possible (if these keys were
|
||||
loaded from a file originally). The single exception is that combined
|
||||
lines will be split into individual key lines, which is arguably a bug.
|
||||
|
@ -314,7 +237,7 @@ class HostKeys (UserDict.DictMixin):
|
|||
|
||||
def hash_host(hostname, salt=None):
|
||||
"""
|
||||
Return a "hashed" form of the hostname, as used by openssh when storing
|
||||
Return a "hashed" form of the hostname, as used by OpenSSH when storing
|
||||
hashed hostnames in the known_hosts file.
|
||||
|
||||
:param hostname: the hostname to hash
|
||||
|
@ -336,3 +259,75 @@ class HostKeys (UserDict.DictMixin):
|
|||
return hostkey.replace('\n', '')
|
||||
hash_host = staticmethod(hash_host)
|
||||
|
||||
|
||||
class InvalidHostKey(Exception):
|
||||
def __init__(self, line, exc):
|
||||
self.line = line
|
||||
self.exc = exc
|
||||
self.args = (line, exc)
|
||||
|
||||
|
||||
class HostKeyEntry:
|
||||
"""
|
||||
Representation of a line in an OpenSSH-style "known hosts" file.
|
||||
"""
|
||||
|
||||
def __init__(self, hostnames=None, key=None):
|
||||
self.valid = (hostnames is not None) and (key is not None)
|
||||
self.hostnames = hostnames
|
||||
self.key = key
|
||||
|
||||
def from_line(cls, line, lineno=None):
|
||||
"""
|
||||
Parses the given line of text to find the names for the host,
|
||||
the type of key, and the key data. The line is expected to be in the
|
||||
format used by the OpenSSH known_hosts file.
|
||||
|
||||
Lines are expected to not have leading or trailing whitespace.
|
||||
We don't bother to check for comments or empty lines. All of
|
||||
that should be taken care of before sending the line to us.
|
||||
|
||||
:param line: a line from an OpenSSH known_hosts file
|
||||
:type line: str
|
||||
"""
|
||||
log = get_logger('paramiko.hostkeys')
|
||||
fields = line.split(' ')
|
||||
if len(fields) < 3:
|
||||
# Bad number of fields
|
||||
log.info("Not enough fields found in known_hosts in line %s (%r)" %
|
||||
(lineno, line))
|
||||
return None
|
||||
fields = fields[:3]
|
||||
|
||||
names, keytype, key = fields
|
||||
names = names.split(',')
|
||||
|
||||
# Decide what kind of key we're looking at and create an object
|
||||
# to hold it accordingly.
|
||||
try:
|
||||
if keytype == 'ssh-rsa':
|
||||
key = RSAKey(data=base64.decodestring(key))
|
||||
elif keytype == 'ssh-dss':
|
||||
key = DSSKey(data=base64.decodestring(key))
|
||||
else:
|
||||
log.info("Unable to handle key of type %s" % (keytype,))
|
||||
return None
|
||||
except binascii.Error, e:
|
||||
raise InvalidHostKey(line, e)
|
||||
|
||||
return cls(names, key)
|
||||
from_line = classmethod(from_line)
|
||||
|
||||
def to_line(self):
|
||||
"""
|
||||
Returns a string in OpenSSH known_hosts file format, or None if
|
||||
the object is not in a valid state. A trailing newline is
|
||||
included.
|
||||
"""
|
||||
if self.valid:
|
||||
return '%s %s %s\n' % (','.join(self.hostnames), self.key.get_name(),
|
||||
self.key.get_base64())
|
||||
return None
|
||||
|
||||
def __repr__(self):
|
||||
return '<HostKeyEntry %r: %r>' % (self.hostnames, self.key)
|
||||
|
|
|
@ -2,3 +2,4 @@ Host keys / ``known_hosts`` files
|
|||
=================================
|
||||
|
||||
.. automodule:: paramiko.hostkeys
|
||||
:member-order: bysource
|
||||
|
|
Loading…
Reference in New Issue