xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #2097: _sshfp_policy.py

File _sshfp_policy.py, 1.8 KB (added by elenril, 3 years ago)
Line 
1import hashlib
2
3from dns import flags, rdatatype, resolver as dnsres
4
5from paramiko.client import MissingHostKeyPolicy
6from paramiko.common import DEBUG
7
8_key_algorithms = {
9    'ssh-rsa' : '1',
10    'ssh-dss' : '2',
11    'ecdsa-sha2-nistp256' : '3',
12    'ecdsa-sha2-nistp384' : '3',
13    'ecdsa-sha2-nistp521' : '3',
14    'ssh-ed25519' : '4',
15}
16
17_hash_funcs = {
18    '1' : hashlib.sha1,
19    '2' : hashlib.sha256,
20}
21
22class SSHFPPolicy(MissingHostKeyPolicy):
23    '''Checks for a matching SSHFP RR'''
24    def __init__(self, resolver = None):
25        if resolver is None:
26            resolver = dnsres.Resolver()
27            resolver.use_edns(0, flags.DO, 1280)
28
29        self._resolver = resolver
30
31    def missing_host_key(self, client, hostname, key):
32        try:
33            key_alg = _key_algorithms[key.get_name()]
34        except KeyError:
35            raise Exception('Unsupported key type for SSHFP: %s' % key.get_name())
36
37        try:
38            resp = self._resolver.query(hostname, 'SSHFP')
39        except dnsres.NoAnswer:
40            raise Exception('Could not obtain SSHFP records for host: %s' % hostname)
41
42        if not resp.response.flags & flags.AD:
43            raise Exception('Answer does not have a valid DNSSEC signature')
44
45        for item in resp:
46            try:
47                alg, fg_type, fg = item.to_text().split()
48            except ValueError:
49                raise Exception('Invalid SSHFP record format: %s' % item.to_text())
50
51            if alg != key_alg:
52                continue
53
54            if not fg_type in _hash_funcs:
55                continue
56
57            fg_expect = _hash_funcs[fg_type](key.asbytes()).hexdigest()
58            if fg_expect == fg:
59                client._log(DEBUG, 'Found valid SSHFP record for host %s' % hostname)
60                return
61        raise Exception('No matching SSHFP records found')