test_openssh_compat.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.conch.openssh_compat}.
  5. """
  6. import os
  7. from twisted.trial.unittest import TestCase
  8. from twisted.python.filepath import FilePath
  9. from twisted.python.reflect import requireModule
  10. if requireModule('cryptography') and requireModule('pyasn1'):
  11. from twisted.conch.openssh_compat.factory import OpenSSHFactory
  12. else:
  13. OpenSSHFactory = None
  14. from twisted.conch.ssh._kex import getDHGeneratorAndPrime
  15. from twisted.conch.test import keydata
  16. from twisted.test.test_process import MockOS
  17. class OpenSSHFactoryTests(TestCase):
  18. """
  19. Tests for L{OpenSSHFactory}.
  20. """
  21. if getattr(os, "geteuid", None) is None:
  22. skip = "geteuid/seteuid not available"
  23. elif OpenSSHFactory is None:
  24. skip = "Cannot run without cryptography or PyASN1"
  25. def setUp(self):
  26. self.factory = OpenSSHFactory()
  27. self.keysDir = FilePath(self.mktemp())
  28. self.keysDir.makedirs()
  29. self.factory.dataRoot = self.keysDir.path
  30. self.moduliDir = FilePath(self.mktemp())
  31. self.moduliDir.makedirs()
  32. self.factory.moduliRoot = self.moduliDir.path
  33. self.keysDir.child("ssh_host_foo").setContent(b"foo")
  34. self.keysDir.child("bar_key").setContent(b"foo")
  35. self.keysDir.child("ssh_host_one_key").setContent(
  36. keydata.privateRSA_openssh)
  37. self.keysDir.child("ssh_host_two_key").setContent(
  38. keydata.privateDSA_openssh)
  39. self.keysDir.child("ssh_host_three_key").setContent(
  40. b"not a key content")
  41. self.keysDir.child("ssh_host_one_key.pub").setContent(
  42. keydata.publicRSA_openssh)
  43. self.moduliDir.child("moduli").setContent(b"""
  44. # $OpenBSD: moduli,v 1.xx 2016/07/26 12:34:56 jhacker Exp $
  45. # Time Type Tests Tries Size Generator Modulus
  46. 20030501000000 2 6 100 2047 2 FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF
  47. """)
  48. self.mockos = MockOS()
  49. self.patch(os, "seteuid", self.mockos.seteuid)
  50. self.patch(os, "setegid", self.mockos.setegid)
  51. def test_getPublicKeys(self):
  52. """
  53. L{OpenSSHFactory.getPublicKeys} should return the available public keys
  54. in the data directory
  55. """
  56. keys = self.factory.getPublicKeys()
  57. self.assertEqual(len(keys), 1)
  58. keyTypes = keys.keys()
  59. self.assertEqual(list(keyTypes), [b'ssh-rsa'])
  60. def test_getPrivateKeys(self):
  61. """
  62. Will return the available private keys in the data directory, ignoring
  63. key files which failed to be loaded.
  64. """
  65. keys = self.factory.getPrivateKeys()
  66. self.assertEqual(len(keys), 2)
  67. keyTypes = keys.keys()
  68. self.assertEqual(set(keyTypes), set([b'ssh-rsa', b'ssh-dss']))
  69. self.assertEqual(self.mockos.seteuidCalls, [])
  70. self.assertEqual(self.mockos.setegidCalls, [])
  71. def test_getPrivateKeysAsRoot(self):
  72. """
  73. L{OpenSSHFactory.getPrivateKeys} should switch to root if the keys
  74. aren't readable by the current user.
  75. """
  76. keyFile = self.keysDir.child("ssh_host_two_key")
  77. # Fake permission error by changing the mode
  78. keyFile.chmod(0000)
  79. self.addCleanup(keyFile.chmod, 0o777)
  80. # And restore the right mode when seteuid is called
  81. savedSeteuid = os.seteuid
  82. def seteuid(euid):
  83. keyFile.chmod(0o777)
  84. return savedSeteuid(euid)
  85. self.patch(os, "seteuid", seteuid)
  86. keys = self.factory.getPrivateKeys()
  87. self.assertEqual(len(keys), 2)
  88. keyTypes = keys.keys()
  89. self.assertEqual(set(keyTypes), set([b'ssh-rsa', b'ssh-dss']))
  90. self.assertEqual(self.mockos.seteuidCalls, [0, os.geteuid()])
  91. self.assertEqual(self.mockos.setegidCalls, [0, os.getegid()])
  92. def test_getPrimes(self):
  93. """
  94. L{OpenSSHFactory.getPrimes} should return the available primes
  95. in the moduli directory.
  96. """
  97. primes = self.factory.getPrimes()
  98. self.assertEqual(primes, {
  99. 2048: [getDHGeneratorAndPrime(b"diffie-hellman-group14-sha1")],
  100. })