test_rsax931.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. # coding: utf-8
  2. """
  3. Test the RSA ANSI X9.31 signer and verifier
  4. """
  5. # python libs
  6. from __future__ import absolute_import, print_function, unicode_literals
  7. import ctypes
  8. import ctypes.util
  9. import fnmatch
  10. import glob
  11. import os
  12. import platform
  13. import sys
  14. import salt.utils.platform
  15. # salt libs
  16. from salt.utils.rsax931 import (
  17. RSAX931Signer,
  18. RSAX931Verifier,
  19. _find_libcrypto,
  20. _load_libcrypto,
  21. )
  22. from tests.support.mock import patch
  23. # salt testing libs
  24. from tests.support.unit import TestCase, skipIf
  25. class RSAX931Test(TestCase):
  26. privkey_data = (
  27. "-----BEGIN RSA PRIVATE KEY-----\n"
  28. "MIIEpAIBAAKCAQEA75GR6ZTv5JOv90Vq8tKhKC7YQnhDIo2hM0HVziTEk5R4UQBW\n"
  29. "a0CKytFMbTONY2msEDwX9iA0x7F5Lgj0X8eD4ZMsYqLzqjWMekLC8bjhxc+EuPo9\n"
  30. "Dygu3mJ2VgRC7XhlFpmdo5NN8J2E7B/CNB3R4hOcMMZNZdi0xLtFoTfwU61UPfFX\n"
  31. "14mV2laqLbvDEfQLJhUTDeFFV8EN5Z4H1ttLP3sMXJvc3EvM0JiDVj4l1TWFUHHz\n"
  32. "eFgCA1Im0lv8i7PFrgW7nyMfK9uDSsUmIp7k6ai4tVzwkTmV5PsriP1ju88Lo3MB\n"
  33. "4/sUmDv/JmlZ9YyzTO3Po8Uz3Aeq9HJWyBWHAQIDAQABAoIBAGOzBzBYZUWRGOgl\n"
  34. "IY8QjTT12dY/ymC05GM6gMobjxuD7FZ5d32HDLu/QrknfS3kKlFPUQGDAbQhbbb0\n"
  35. "zw6VL5NO9mfOPO2W/3FaG1sRgBQcerWonoSSSn8OJwVBHMFLG3a+U1Zh1UvPoiPK\n"
  36. "S734swIM+zFpNYivGPvOm/muF/waFf8tF/47t1cwt/JGXYQnkG/P7z0vp47Irpsb\n"
  37. "Yjw7vPe4BnbY6SppSxscW3KoV7GtJLFKIxAXbxsuJMF/rYe3O3w2VKJ1Sug1VDJl\n"
  38. "/GytwAkSUer84WwP2b07Wn4c5pCnmLslMgXCLkENgi1NnJMhYVOnckxGDZk54hqP\n"
  39. "9RbLnkkCgYEA/yKuWEvgdzYRYkqpzB0l9ka7Y00CV4Dha9Of6GjQi9i4VCJ/UFVr\n"
  40. "UlhTo5y0ZzpcDAPcoZf5CFZsD90a/BpQ3YTtdln2MMCL/Kr3QFmetkmDrt+3wYnX\n"
  41. "sKESfsa2nZdOATRpl1antpwyD4RzsAeOPwBiACj4fkq5iZJBSI0bxrMCgYEA8GFi\n"
  42. "qAjgKh81/Uai6KWTOW2kX02LEMVRrnZLQ9VPPLGid4KZDDk1/dEfxjjkcyOxX1Ux\n"
  43. "Klu4W8ZEdZyzPcJrfk7PdopfGOfrhWzkREK9C40H7ou/1jUecq/STPfSOmxh3Y+D\n"
  44. "ifMNO6z4sQAHx8VaHaxVsJ7SGR/spr0pkZL+NXsCgYEA84rIgBKWB1W+TGRXJzdf\n"
  45. "yHIGaCjXpm2pQMN3LmP3RrcuZWm0vBt94dHcrR5l+u/zc6iwEDTAjJvqdU4rdyEr\n"
  46. "tfkwr7v6TNlQB3WvpWanIPyVzfVSNFX/ZWSsAgZvxYjr9ixw6vzWBXOeOb/Gqu7b\n"
  47. "cvpLkjmJ0wxDhbXtyXKhZA8CgYBZyvcQb+hUs732M4mtQBSD0kohc5TsGdlOQ1AQ\n"
  48. "McFcmbpnzDghkclyW8jzwdLMk9uxEeDAwuxWE/UEvhlSi6qdzxC+Zifp5NBc0fVe\n"
  49. "7lMx2mfJGxj5CnSqQLVdHQHB4zSXkAGB6XHbBd0MOUeuvzDPfs2voVQ4IG3FR0oc\n"
  50. "3/znuwKBgQChZGH3McQcxmLA28aUwOVbWssfXKdDCsiJO+PEXXlL0maO3SbnFn+Q\n"
  51. "Tyf8oHI5cdP7AbwDSx9bUfRPjg9dKKmATBFr2bn216pjGxK0OjYOCntFTVr0psRB\n"
  52. "CrKg52Qrq71/2l4V2NLQZU40Dr1bN9V+Ftd9L0pvpCAEAWpIbLXGDw==\n"
  53. "-----END RSA PRIVATE KEY-----"
  54. )
  55. pubkey_data = (
  56. "-----BEGIN PUBLIC KEY-----\n"
  57. "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA75GR6ZTv5JOv90Vq8tKh\n"
  58. "KC7YQnhDIo2hM0HVziTEk5R4UQBWa0CKytFMbTONY2msEDwX9iA0x7F5Lgj0X8eD\n"
  59. "4ZMsYqLzqjWMekLC8bjhxc+EuPo9Dygu3mJ2VgRC7XhlFpmdo5NN8J2E7B/CNB3R\n"
  60. "4hOcMMZNZdi0xLtFoTfwU61UPfFX14mV2laqLbvDEfQLJhUTDeFFV8EN5Z4H1ttL\n"
  61. "P3sMXJvc3EvM0JiDVj4l1TWFUHHzeFgCA1Im0lv8i7PFrgW7nyMfK9uDSsUmIp7k\n"
  62. "6ai4tVzwkTmV5PsriP1ju88Lo3MB4/sUmDv/JmlZ9YyzTO3Po8Uz3Aeq9HJWyBWH\n"
  63. "AQIDAQAB\n"
  64. "-----END PUBLIC KEY-----"
  65. )
  66. hello_world = b"hello, world"
  67. hello_world_sig = (
  68. b"\x63\xa0\x70\xd2\xe4\xd4\x6b\x8a\xa2\x59\x27\x5f\x00\x69"
  69. b"\x1e\x3c\x50\xed\x50\x13\x09\x80\xe3\x47\x4e\x14\xb5\x7c"
  70. b"\x07\x26\x4e\x20\x74\xea\x0e\xf8\xda\xff\x1e\x57\x8c\x67"
  71. b"\x76\x73\xaa\xea\x0f\x0a\xe7\xa2\xe3\x88\xfc\x09\x87\x36"
  72. b"\x01\x3a\xb7\x4c\x40\xe0\xf4\x54\xc5\xf1\xaa\xb2\x1d\x7f"
  73. b"\xb6\xd3\xa8\xdd\x28\x69\x8b\x88\xe4\x42\x1e\x48\x3e\x1f"
  74. b"\xe2\x2b\x3c\x7c\x85\x11\xe9\x59\xd7\xf3\xc2\x21\xd3\x55"
  75. b"\xcb\x9c\x3c\x93\xcc\x20\xdf\x64\x81\xd0\x0d\xbf\x8e\x8d"
  76. b"\x47\xec\x1d\x9e\x27\xec\x12\xed\x8b\x5f\xd6\x1d\xec\x8d"
  77. b"\x77\x5a\x58\x8a\x24\xb6\x0f\x12\xb7\x51\xef\x7d\x85\x0f"
  78. b"\x49\x39\x02\x81\x15\x08\x70\xd6\xe0\x0b\x31\xff\x5f\xf9"
  79. b"\xd1\x92\x38\x59\x8c\x22\x9c\xbb\xbf\xcf\x85\x34\xe2\x47"
  80. b"\xf5\xe2\xaa\xb4\x62\x33\x3c\x13\x78\x33\x87\x08\x9e\xb5"
  81. b"\xbc\x5d\xc1\xbf\x79\x7c\xfa\x5f\x06\x6a\x3b\x17\x40\x09"
  82. b"\xb9\x09\xbf\x32\xc3\x00\xe2\xbc\x91\x77\x14\xa5\x23\xf5"
  83. b"\xf5\xf1\x09\x12\x38\xda\x3b\x6a\x82\x81\x7b\x5e\x1c\xcb"
  84. b"\xaa\x36\x9b\x08\x36\x03\x14\x96\xa3\x31\x39\x59\x16\x75"
  85. b"\xc9\xb6\x66\x94\x1b\x97\xff\xc8\xa1\xe3\x21\x35\x23\x06"
  86. b"\x4c\x9b\xf4\xee"
  87. )
  88. def test_signer(self):
  89. with self.assertRaises(ValueError):
  90. signer = RSAX931Signer("bogus key data")
  91. with self.assertRaises(ValueError):
  92. signer = RSAX931Signer(RSAX931Test.pubkey_data)
  93. signer = RSAX931Signer(RSAX931Test.privkey_data)
  94. with self.assertRaises(ValueError):
  95. signer.sign("x" * 255) # message too long
  96. sig = signer.sign(RSAX931Test.hello_world)
  97. self.assertEqual(RSAX931Test.hello_world_sig, sig)
  98. def test_verifier(self):
  99. with self.assertRaises(ValueError):
  100. verifier = RSAX931Verifier("bogus key data")
  101. with self.assertRaises(ValueError):
  102. verifier = RSAX931Verifier(RSAX931Test.privkey_data)
  103. verifier = RSAX931Verifier(RSAX931Test.pubkey_data)
  104. with self.assertRaises(ValueError):
  105. verifier.verify("")
  106. with self.assertRaises(ValueError):
  107. verifier.verify(RSAX931Test.hello_world_sig + b"junk")
  108. msg = verifier.verify(RSAX931Test.hello_world_sig)
  109. self.assertEqual(RSAX931Test.hello_world, msg)
  110. @skipIf(not salt.utils.platform.is_windows(), "Host OS is not Windows.")
  111. def test_find_libcrypto_win32(self):
  112. """
  113. Test _find_libcrypto on Windows hosts.
  114. """
  115. lib_path = _find_libcrypto()
  116. self.assertEqual(lib_path, "libeay32")
  117. @skipIf(
  118. not getattr(sys, "frozen", False) and not salt.utils.platform.is_smartos(),
  119. "Host OS is not SmartOS.",
  120. )
  121. def test_find_libcrypto_smartos(self):
  122. """
  123. Test _find_libcrypto on a SmartOS host.
  124. """
  125. lib_path = _find_libcrypto()
  126. self.assertTrue(
  127. fnmatch.fnmatch(
  128. lib_path, os.path.join(os.path.dirname(sys.executable), "libcrypto*")
  129. )
  130. )
  131. @skipIf(not salt.utils.platform.is_sunos(), "Host OS is not Solaris-like.")
  132. def test_find_libcrypto_sunos(self):
  133. """
  134. Test _find_libcrypto on a Solaris-like host.
  135. """
  136. lib_path = _find_libcrypto()
  137. passed = False
  138. for i in ("/opt/local/lib/libcrypto.so*", "/opt/tools/lib/libcrypto.so*"):
  139. if fnmatch.fnmatch(lib_path, i):
  140. passed = True
  141. break
  142. self.assertTrue(passed)
  143. @skipIf(not salt.utils.platform.is_aix(), "Host OS is not IBM AIX.")
  144. def test_find_libcrypto_aix(self):
  145. """
  146. Test _find_libcrypto on an IBM AIX host.
  147. """
  148. lib_path = _find_libcrypto()
  149. if os.path.isdir("/opt/salt/lib"):
  150. self.assertTrue(fnmatch.fnmatch(lib_path, "/opt/salt/lib/libcrypto.so*"))
  151. else:
  152. self.assertTrue(
  153. fnmatch.fnmatch(lib_path, "/opt/freeware/lib/libcrypto.so*")
  154. )
  155. @skipIf(not salt.utils.platform.is_darwin(), "Host OS is not Darwin-like or macOS.")
  156. @patch.object(platform, "mac_ver", lambda: ("10.14.2", (), ""))
  157. @patch.object(glob, "glob", lambda _: [])
  158. def test_find_libcrypto_with_system_and_not_catalina(self):
  159. """
  160. Test _find_libcrypto on a Catalina-like macOS host, simulate
  161. not finding any other libcryptos and just defaulting to system.
  162. """
  163. lib_path = _find_libcrypto()
  164. passed = False
  165. for i in (
  166. "/opt/salt/lib/libcrypto.dylib",
  167. "/usr/local/opt/openssl/lib/libcrypto.dylib",
  168. "/usr/local/opt/openssl@*/lib/libcrypto.dylib",
  169. "/opt/local/lib/libcrypto.dylib",
  170. "/usr/lib/libcrypto.*.dylib",
  171. ):
  172. if fnmatch.fnmatch(lib_path, i):
  173. passed = True
  174. break
  175. self.assertFalse(passed)
  176. self.assertEqual(lib_path, "/usr/lib/libcrypto.dylib")
  177. @skipIf(not salt.utils.platform.is_darwin(), "Host OS is not Darwin-like or macOS.")
  178. @patch.object(platform, "mac_ver", lambda: ("10.15.2", (), ""))
  179. def test_find_libcrypto_darwin_catalina(self):
  180. """
  181. Test _find_libcrypto on a Darwin-like macOS host where there isn't a
  182. lacation returned by ctypes.util.find_library()
  183. """
  184. lib_path = _find_libcrypto()
  185. passed = False
  186. for i in (
  187. "/opt/salt/lib/libcrypto.dylib",
  188. "/usr/local/opt/openssl/lib/libcrypto.dylib",
  189. "/usr/local/opt/openssl@*/lib/libcrypto.dylib",
  190. "/opt/local/lib/libcrypto.dylib",
  191. "/usr/lib/libcrypto.*.dylib",
  192. ):
  193. if fnmatch.fnmatch(lib_path, i):
  194. passed = True
  195. break
  196. self.assertTrue(passed)
  197. @patch.object(ctypes.util, "find_library", lambda a: None)
  198. @patch.object(glob, "glob", lambda a: [])
  199. @patch.object(sys, "platform", "unknown")
  200. @patch.object(salt.utils.platform, "is_darwin", lambda: False)
  201. def test_find_libcrypto_unsupported(self):
  202. """
  203. Ensure that _find_libcrypto works correctly on an unsupported host OS.
  204. """
  205. with self.assertRaises(OSError):
  206. _find_libcrypto()
  207. def test_load_libcrypto(self):
  208. """
  209. Test _load_libcrypto generically.
  210. """
  211. lib = _load_libcrypto()
  212. self.assertTrue(isinstance(lib, ctypes.CDLL))
  213. # Try to cover both pre and post OpenSSL 1.1.
  214. self.assertTrue(
  215. hasattr(lib, "OpenSSL_version_num")
  216. or hasattr(lib, "OPENSSL_init_crypto")
  217. or hasattr(lib, "OPENSSL_no_config")
  218. )