Support ssh-keygen of OpenSSH 6.8

OpenSSH 6.8 changed the default hash method to SHA256. OpenSSH 6.7 and
older don't support the -E command line option to specify the hash
method.

First try without -E since most Linux distribution for OpenStack Kilo
still use OpenSSH 6.7. If OpenSSH 6.8 and newer is detected (hash method
specified in the output), call again ssh-keygen with -E md5 to hash the
fingerprint using MD5.

This change fixes the two following tests on Fedora 22:

* nova.tests.unit.api.ec2.test_cloud.CloudTestCase.test_import_key_pair
* nova.tests.unit.compute.test_keypairs.ImportKeypairTestCase.test_success_ssh

Add two unit tests mocking OpenSSH 6.7 and 6.8 outputs.

Closes-bug: #1464298
Change-Id: I867684c36377e5c1e5ca5d33e3fc2f1795f44e06
This commit is contained in:
Victor Stinner 2015-06-15 16:10:45 +02:00
parent d22167e083
commit 8280575b0b
2 changed files with 56 additions and 1 deletions

View File

@ -127,8 +127,19 @@ def ensure_ca_filesystem():
def _generate_fingerprint(public_key_file):
(out, err) = utils.execute('ssh-keygen', '-q', '-l', '-f', public_key_file)
# NOTE(haypo): OpenSSH 6.7 and older doesn't support the -E option to
# specify the hash method. First try without -E since most Linux
# distribution for OpenStack Kilo still use OpenSSH 6.7.
args = ('ssh-keygen', '-q', '-l', '-f', public_key_file)
(out, err) = utils.execute(*args)
fingerprint = out.split(' ')[1]
if fingerprint.startswith('SHA256:'):
# OpenSSH 6.8 and newer uses SHA256 by default: hash the fingerprint
# using MD5 for backward compatibility
(out, err) = utils.execute(*(args + ('-E', 'md5')))
fingerprint = out.split(' ')[1]
# strip the hash method ("MD5:" prefix)
fingerprint = fingerprint[4:]
return fingerprint

View File

@ -264,3 +264,47 @@ class ConversionTests(test.TestCase):
def test_convert_failure(self):
self.assertRaises(exception.EncryptionFailure,
crypto.convert_from_sshrsa_to_pkcs8, '')
class FingerprintTests(test.TestCase):
@mock.patch.object(utils, 'execute')
def test_openssh_67(self, mock_execute):
# test ssh-keygen of OpenSSH 6.7 and older
mock_execute.side_effect = [
(('2048 67:6e:f8:21:5c:b4:d5:95:74:54:e4:9e:f8:63:7d:60 '
'test (RSA)',
'')),
]
fingerprint = crypto.generate_fingerprint('public key')
self.assertEqual('67:6e:f8:21:5c:b4:d5:95:74:54:e4:9e:f8:63:7d:60',
fingerprint)
self.assertEqual(1, len(mock_execute.call_args_list),
mock_execute.call_args)
self.assertEqual([('ssh-keygen', '-q', '-l', '-f', mock.ANY)],
mock_execute.call_args_list[0])
@mock.patch.object(utils, 'execute')
def test_openssh_68(self, mock_execute):
# test ssh-keygen of OpenSSH 6.8 and newer
mock_execute.side_effect = [
(('2048 SHA256:p3Wk0H3odRa1ugL+7YNP5PC9R/OkUKlY6/6/Md2+yho '
'test (RSA)\n',
'')),
(('2048 MD5:b7:7d:ca:d5:31:9c:27:c6:b4:60:b2:d0:fa:0d:b4:9d '
'test (RSA)\n',
'')),
]
fingerprint = crypto.generate_fingerprint('public key')
self.assertEqual('b7:7d:ca:d5:31:9c:27:c6:b4:60:b2:d0:fa:0d:b4:9d',
fingerprint)
self.assertEqual(2, len(mock_execute.call_args_list),
mock_execute.call_args)
self.assertEqual([('ssh-keygen', '-q', '-l', '-f', mock.ANY)],
mock_execute.call_args_list[0])
self.assertEqual([('ssh-keygen', '-q', '-l', '-f', mock.ANY,
'-E', 'md5')],
mock_execute.call_args_list[1])