# HG changeset patch # User Matt Johnston # Date 1648564157 -28800 # Node ID 43ebe0028187aca75271f98b7a357c5a00587f06 # Parent eadd023fde4d72c210b67c7288237ce329e40fc2 Add tests for dropbearconvert diff -r eadd023fde4d -r 43ebe0028187 test/conftest.py --- 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 diff -r eadd023fde4d -r 43ebe0028187 test/test_dropbearconvert.py --- /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) + +@pytest.mark.parametrize("keytype", keytypes) +@pytest.mark.parametrize("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 + +@pytest.mark.parametrize("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()