changeset 1909:43ebe0028187

Add tests for dropbearconvert
author Matt Johnston <matt@ucc.asn.au>
date Tue, 29 Mar 2022 22:29:17 +0800
parents eadd023fde4d
children 54a85bbe5017
files test/conftest.py test/test_dropbearconvert.py
diffstat 2 files changed, 141 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/test/conftest.py	Tue Mar 29 22:27:55 2022 +0800
+++ b/test/conftest.py	Tue Mar 29 22:29:17 2022 +0800
@@ -2,9 +2,12 @@
     parser.addoption("--port", type=str, help="default is 2244 local, 22 remote")
     parser.addoption("--dbclient", type=str, default="../dbclient")
     parser.addoption("--dropbear", type=str, default="../dropbear")
+    parser.addoption("--dropbearconvert", type=str, default="../dropbearconvert")
+    parser.addoption("--dropbearkey", type=str, default="../dropbearkey")
     parser.addoption("--hostkey", type=str, help="required unless --remote")
     parser.addoption("--remote", type=str, help="remote host")
     parser.addoption("--user", type=str, help="optional username")
+    parser.addoption("--ssh-keygen", type=str, default="ssh-keygen")
 
 def pytest_configure(config):
     opt = config.option
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test_dropbearconvert.py	Tue Mar 29 22:29:17 2022 +0800
@@ -0,0 +1,138 @@
+import subprocess
+import tempfile
+
+import pytest
+
+keytypes = [
+	"rsa", "rsa-4096",
+	"ed25519",
+	"ecdsa", "ecdsa-256", "ecdsa-384", "ecdsa-521",
+	"dss",
+	]
+
+def parse_keytype(kt):
+	if '-' in kt:
+		return kt.split('-')
+	else:
+		return (kt, None)
+
[email protected]("keytype", keytypes)
[email protected]("keyformat", [None, "PEM"])
+def test_from_openssh(request, tmp_path, keytype, keyformat):
+	"""
+	Convert OpenSSH to Dropbear format,
+	PEM and OpenSSH internal
+	"""
+	opt = request.config.option
+	kt, keybits = parse_keytype(keytype)
+
+	if kt == 'dss' and keyformat is None:
+		pytest.xfail("dss doesn't support openssh format")
+
+	if kt == 'ecdsa' and keyformat is None:
+		pytest.skip("ecdsa doesn't support openssh format yet")
+
+	os_kt = kt
+	if os_kt == 'dss':
+		# OpenSSH calls it 'dsa', Dropbear calls it 'dss'
+		os_kt = 'dsa'
+
+	os_key = tmp_path / 'oskey1'
+	db_key = tmp_path / 'dbkey1'
+
+	# Generate an OpenSSH key
+	args = [
+		opt.ssh_keygen,
+		'-f', os_key,
+		'-t', os_kt,
+		'-N', '', # no password
+	]
+	if keybits is not None:
+		args += ['-b', keybits]
+	if keyformat:
+		args += ['-m', keyformat]
+	p = subprocess.run(args, check=True)
+
+	# Convert to dropbear format
+	args = [
+		opt.dropbearconvert,
+		'openssh', 'dropbear',
+		os_key, db_key,
+	]
+	p = subprocess.run(args, check=True)
+
+	# Compare pubkeys
+	args = [
+		opt.dropbearkey,
+		'-f', db_key,
+		'-y'
+	]
+	p = subprocess.run(args, check=True, stdout=subprocess.PIPE, text=True)
+	db_pubkey = p.stdout.splitlines()[1].strip()
+	os_pubkey = os_key.with_suffix('.pub').open().read().strip()
+	# we compare the whole key including comment since it currently matches
+	assert db_pubkey == os_pubkey
+
[email protected]("keytype", keytypes)
+def test_roundtrip(request, tmp_path, keytype):
+	"""
+	Dropbear's private key format is deterministic so
+	we can compare round trip conversion. (OpenSSH's
+	format has more variable comments and other fields).
+	"""
+	opt = request.config.option
+	kt, keybits = parse_keytype(keytype)
+
+	os_key = tmp_path / 'oskey1'
+	db_key1 = tmp_path / 'dbkey1'
+	db_key2 = tmp_path / 'dbkey2'
+
+	# generate a key
+	args = [
+		opt.dropbearkey,
+		'-t', kt,
+		'-f', db_key1,
+	]
+	if keybits is not None:
+		args += ['-s', keybits]
+	p = subprocess.run(args, check=True)
+
+	# convert to openssh
+	args = [
+		opt.dropbearconvert,
+		'dropbear', 'openssh',
+		db_key1, os_key,
+	]
+	p = subprocess.run(args, check=True)
+
+	# Check ssh-keygen can read it
+	args = [
+		opt.ssh_keygen,
+		'-f', os_key,
+		'-y',
+	]
+	p = subprocess.run(args, check=True, text=True, stdout=subprocess.PIPE)
+	os_pubkey = p.stdout.strip()
+
+	# Compare public keys
+	args = [
+		opt.dropbearkey,
+		'-f', db_key1,
+		'-y',
+	]
+	p = subprocess.run(args, check=True, text=True, stdout=subprocess.PIPE)
+	db_pubkey = p.stdout.splitlines()[1].strip()
+	# comment may differ
+	db_pubkey = db_pubkey.split(' ')[:2]
+	os_pubkey = os_pubkey.split(' ')[:2]
+	assert db_pubkey == os_pubkey
+
+	# convert back to dropbear
+	args = [
+		opt.dropbearconvert,
+		'openssh', 'dropbear',
+		os_key, db_key2,
+	]
+	p = subprocess.run(args, check=True)
+	# check the round trip is identical
+	assert db_key1.open('rb').read() == db_key2.open('rb').read()