test_dropbearconvert.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import subprocess
  2. import tempfile
  3. import pytest
  4. keytypes = [
  5. "rsa", "rsa-4096",
  6. "ed25519",
  7. "ecdsa", "ecdsa-256", "ecdsa-384", "ecdsa-521",
  8. "dss",
  9. ]
  10. def parse_keytype(kt):
  11. if '-' in kt:
  12. return kt.split('-')
  13. else:
  14. return (kt, None)
  15. @pytest.mark.parametrize("keytype", keytypes)
  16. @pytest.mark.parametrize("keyformat", [None, "PEM"])
  17. def test_from_openssh(request, tmp_path, keytype, keyformat):
  18. """
  19. Convert OpenSSH to Dropbear format,
  20. PEM and OpenSSH internal
  21. """
  22. opt = request.config.option
  23. kt, keybits = parse_keytype(keytype)
  24. if kt == 'dss' and keyformat is None:
  25. pytest.skip("dss doesn't support openssh format")
  26. os_kt = kt
  27. if os_kt == 'dss':
  28. # OpenSSH calls it 'dsa', Dropbear calls it 'dss'
  29. os_kt = 'dsa'
  30. os_key = tmp_path / 'oskey1'
  31. db_key = tmp_path / 'dbkey1'
  32. # Generate an OpenSSH key
  33. args = [
  34. opt.ssh_keygen,
  35. '-f', os_key,
  36. '-t', os_kt,
  37. '-N', '', # no password
  38. ]
  39. if keybits is not None:
  40. args += ['-b', keybits]
  41. if keyformat:
  42. args += ['-m', keyformat]
  43. p = subprocess.run(args, check=True)
  44. # Convert to dropbear format
  45. args = [
  46. opt.dropbearconvert,
  47. 'openssh', 'dropbear',
  48. os_key, db_key,
  49. ]
  50. p = subprocess.run(args, check=True)
  51. # Compare pubkeys
  52. args = [
  53. opt.dropbearkey,
  54. '-f', db_key,
  55. '-y'
  56. ]
  57. p = subprocess.run(args, check=True, stdout=subprocess.PIPE, text=True)
  58. db_pubkey = p.stdout.splitlines()[1].strip()
  59. os_pubkey = os_key.with_suffix('.pub').open().read().strip()
  60. # we compare the whole key including comment since it currently matches
  61. assert db_pubkey == os_pubkey
  62. @pytest.mark.parametrize("keytype", keytypes)
  63. def test_roundtrip(request, tmp_path, keytype):
  64. """
  65. Dropbear's private key format is deterministic so
  66. we can compare round trip conversion. (OpenSSH's
  67. format has more variable comments and other fields).
  68. """
  69. opt = request.config.option
  70. kt, keybits = parse_keytype(keytype)
  71. os_key = tmp_path / 'oskey1'
  72. db_key1 = tmp_path / 'dbkey1'
  73. db_key2 = tmp_path / 'dbkey2'
  74. # generate a key
  75. args = [
  76. opt.dropbearkey,
  77. '-t', kt,
  78. '-f', db_key1,
  79. ]
  80. if keybits is not None:
  81. args += ['-s', keybits]
  82. p = subprocess.run(args, check=True)
  83. # convert to openssh
  84. args = [
  85. opt.dropbearconvert,
  86. 'dropbear', 'openssh',
  87. db_key1, os_key,
  88. ]
  89. p = subprocess.run(args, check=True)
  90. # Check ssh-keygen can read it
  91. args = [
  92. opt.ssh_keygen,
  93. '-f', os_key,
  94. '-y',
  95. ]
  96. p = subprocess.run(args, check=True, text=True, stdout=subprocess.PIPE)
  97. os_pubkey = p.stdout.strip()
  98. # Compare public keys
  99. args = [
  100. opt.dropbearkey,
  101. '-f', db_key1,
  102. '-y',
  103. ]
  104. p = subprocess.run(args, check=True, text=True, stdout=subprocess.PIPE)
  105. db_pubkey = p.stdout.splitlines()[1].strip()
  106. # comment may differ
  107. db_pubkey = db_pubkey.split(' ')[:2]
  108. os_pubkey = os_pubkey.split(' ')[:2]
  109. assert db_pubkey == os_pubkey
  110. # convert back to dropbear
  111. args = [
  112. opt.dropbearconvert,
  113. 'openssh', 'dropbear',
  114. os_key, db_key2,
  115. ]
  116. p = subprocess.run(args, check=True)
  117. # check the round trip is identical
  118. assert db_key1.open('rb').read() == db_key2.open('rb').read()