You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

362 rivejä
13 KiB

  1. try:
  2. import unittest2 as unittest
  3. except ImportError:
  4. import unittest
  5. import base64
  6. import pytest
  7. from .curves import (
  8. Curve,
  9. NIST256p,
  10. curves,
  11. UnknownCurveError,
  12. PRIME_FIELD_OID,
  13. curve_by_name,
  14. )
  15. from .ellipticcurve import CurveFp, PointJacobi, CurveEdTw
  16. from . import der
  17. from .util import number_to_string
  18. class TestParameterEncoding(unittest.TestCase):
  19. @classmethod
  20. def setUpClass(cls):
  21. # minimal, but with cofactor (excludes seed when compared to
  22. # OpenSSL output)
  23. cls.base64_params = (
  24. "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////"
  25. "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K"
  26. "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd"
  27. "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1"
  28. "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE="
  29. )
  30. def test_from_pem(self):
  31. pem_params = (
  32. "-----BEGIN EC PARAMETERS-----\n"
  33. "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////\n"
  34. "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K\n"
  35. "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd\n"
  36. "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1\n"
  37. "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=\n"
  38. "-----END EC PARAMETERS-----\n"
  39. )
  40. curve = Curve.from_pem(pem_params)
  41. self.assertIs(curve, NIST256p)
  42. def test_from_pem_with_explicit_when_explicit_disabled(self):
  43. pem_params = (
  44. "-----BEGIN EC PARAMETERS-----\n"
  45. "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////\n"
  46. "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K\n"
  47. "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd\n"
  48. "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1\n"
  49. "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=\n"
  50. "-----END EC PARAMETERS-----\n"
  51. )
  52. with self.assertRaises(der.UnexpectedDER) as e:
  53. Curve.from_pem(pem_params, ["named_curve"])
  54. self.assertIn("explicit curve parameters not", str(e.exception))
  55. def test_from_pem_with_named_curve_with_named_curve_disabled(self):
  56. pem_params = (
  57. "-----BEGIN EC PARAMETERS-----\n"
  58. "BggqhkjOPQMBBw==\n"
  59. "-----END EC PARAMETERS-----\n"
  60. )
  61. with self.assertRaises(der.UnexpectedDER) as e:
  62. Curve.from_pem(pem_params, ["explicit"])
  63. self.assertIn("named_curve curve parameters not", str(e.exception))
  64. def test_from_pem_with_wrong_header(self):
  65. pem_params = (
  66. "-----BEGIN PARAMETERS-----\n"
  67. "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////\n"
  68. "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K\n"
  69. "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd\n"
  70. "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1\n"
  71. "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=\n"
  72. "-----END PARAMETERS-----\n"
  73. )
  74. with self.assertRaises(der.UnexpectedDER) as e:
  75. Curve.from_pem(pem_params)
  76. self.assertIn("PARAMETERS PEM header", str(e.exception))
  77. def test_to_pem(self):
  78. pem_params = (
  79. b"-----BEGIN EC PARAMETERS-----\n"
  80. b"BggqhkjOPQMBBw==\n"
  81. b"-----END EC PARAMETERS-----\n"
  82. )
  83. encoding = NIST256p.to_pem()
  84. self.assertEqual(pem_params, encoding)
  85. def test_compare_with_different_object(self):
  86. self.assertNotEqual(NIST256p, 256)
  87. def test_named_curve_params_der(self):
  88. encoded = NIST256p.to_der()
  89. # just the encoding of the NIST256p OID (prime256v1)
  90. self.assertEqual(b"\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07", encoded)
  91. def test_verify_that_default_is_named_curve_der(self):
  92. encoded_default = NIST256p.to_der()
  93. encoded_named = NIST256p.to_der("named_curve")
  94. self.assertEqual(encoded_default, encoded_named)
  95. def test_encoding_to_explicit_params(self):
  96. encoded = NIST256p.to_der("explicit")
  97. self.assertEqual(encoded, bytes(base64.b64decode(self.base64_params)))
  98. def test_encoding_to_unsupported_type(self):
  99. with self.assertRaises(ValueError) as e:
  100. NIST256p.to_der("unsupported")
  101. self.assertIn("Only 'named_curve'", str(e.exception))
  102. def test_encoding_to_explicit_compressed_params(self):
  103. encoded = NIST256p.to_der("explicit", "compressed")
  104. compressed_base_point = (
  105. "MIHAAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////"
  106. "/////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6"
  107. "k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEIQNrF9Hy4SxCR/i85uVjpEDydwN9"
  108. "gS3rM6D0oTlF2JjClgIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8YyVR"
  109. "AgEB"
  110. )
  111. self.assertEqual(
  112. encoded, bytes(base64.b64decode(compressed_base_point))
  113. )
  114. def test_decoding_explicit_from_openssl(self):
  115. # generated with openssl 1.1.1k using
  116. # openssl ecparam -name P-256 -param_enc explicit -out /tmp/file.pem
  117. p256_explicit = (
  118. "MIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////"
  119. "/////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6"
  120. "k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9+"
  121. "kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT+NC4v4af5uO5+tK"
  122. "fA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAAAP//////////vOb6racXnoTz"
  123. "ucrC/GMlUQIBAQ=="
  124. )
  125. decoded = Curve.from_der(bytes(base64.b64decode(p256_explicit)))
  126. self.assertEqual(NIST256p, decoded)
  127. def test_decoding_well_known_from_explicit_params(self):
  128. curve = Curve.from_der(bytes(base64.b64decode(self.base64_params)))
  129. self.assertIs(curve, NIST256p)
  130. def test_decoding_with_incorrect_valid_encodings(self):
  131. with self.assertRaises(ValueError) as e:
  132. Curve.from_der(b"", ["explicitCA"])
  133. self.assertIn("Only named_curve", str(e.exception))
  134. def test_compare_curves_with_different_generators(self):
  135. curve_fp = CurveFp(23, 1, 7)
  136. base_a = PointJacobi(curve_fp, 13, 3, 1, 9, generator=True)
  137. base_b = PointJacobi(curve_fp, 1, 20, 1, 9, generator=True)
  138. curve_a = Curve("unknown", curve_fp, base_a, None)
  139. curve_b = Curve("unknown", curve_fp, base_b, None)
  140. self.assertNotEqual(curve_a, curve_b)
  141. def test_default_encode_for_custom_curve(self):
  142. curve_fp = CurveFp(23, 1, 7)
  143. base_point = PointJacobi(curve_fp, 13, 3, 1, 9, generator=True)
  144. curve = Curve("unknown", curve_fp, base_point, None)
  145. encoded = curve.to_der()
  146. decoded = Curve.from_der(encoded)
  147. self.assertEqual(curve, decoded)
  148. expected = "MCECAQEwDAYHKoZIzj0BAQIBFzAGBAEBBAEHBAMEDQMCAQk="
  149. self.assertEqual(encoded, bytes(base64.b64decode(expected)))
  150. def test_named_curve_encode_for_custom_curve(self):
  151. curve_fp = CurveFp(23, 1, 7)
  152. base_point = PointJacobi(curve_fp, 13, 3, 1, 9, generator=True)
  153. curve = Curve("unknown", curve_fp, base_point, None)
  154. with self.assertRaises(UnknownCurveError) as e:
  155. curve.to_der("named_curve")
  156. self.assertIn("Can't encode curve", str(e.exception))
  157. def test_try_decoding_binary_explicit(self):
  158. sect113r1_explicit = (
  159. "MIGRAgEBMBwGByqGSM49AQIwEQIBcQYJKoZIzj0BAgMCAgEJMDkEDwAwiCUMpufH"
  160. "/mSc6Fgg9wQPAOi+5NPiJgdEGIvg6ccjAxUAEOcjqxTWluZ2h1YVF1b+v4/LSakE"
  161. "HwQAnXNhbzX0qxQH1zViwQ8ApSgwJ3lY7oTRMV7TGIYCDwEAAAAAAAAA2czsijnl"
  162. "bwIBAg=="
  163. )
  164. with self.assertRaises(UnknownCurveError) as e:
  165. Curve.from_der(base64.b64decode(sect113r1_explicit))
  166. self.assertIn("Characteristic 2 curves unsupported", str(e.exception))
  167. def test_decode_malformed_named_curve(self):
  168. bad_der = der.encode_oid(*NIST256p.oid) + der.encode_integer(1)
  169. with self.assertRaises(der.UnexpectedDER) as e:
  170. Curve.from_der(bad_der)
  171. self.assertIn("Unexpected data after OID", str(e.exception))
  172. def test_decode_malformed_explicit_garbage_after_ECParam(self):
  173. bad_der = bytes(
  174. base64.b64decode(self.base64_params)
  175. ) + der.encode_integer(1)
  176. with self.assertRaises(der.UnexpectedDER) as e:
  177. Curve.from_der(bad_der)
  178. self.assertIn("Unexpected data after ECParameters", str(e.exception))
  179. def test_decode_malformed_unknown_version_number(self):
  180. bad_der = der.encode_sequence(der.encode_integer(2))
  181. with self.assertRaises(der.UnexpectedDER) as e:
  182. Curve.from_der(bad_der)
  183. self.assertIn("Unknown parameter encoding format", str(e.exception))
  184. def test_decode_malformed_unknown_field_type(self):
  185. curve_p = NIST256p.curve.p()
  186. bad_der = der.encode_sequence(
  187. der.encode_integer(1),
  188. der.encode_sequence(
  189. der.encode_oid(1, 2, 3), der.encode_integer(curve_p)
  190. ),
  191. der.encode_sequence(
  192. der.encode_octet_string(
  193. number_to_string(NIST256p.curve.a() % curve_p, curve_p)
  194. ),
  195. der.encode_octet_string(
  196. number_to_string(NIST256p.curve.b(), curve_p)
  197. ),
  198. ),
  199. der.encode_octet_string(
  200. NIST256p.generator.to_bytes("uncompressed")
  201. ),
  202. der.encode_integer(NIST256p.generator.order()),
  203. )
  204. with self.assertRaises(UnknownCurveError) as e:
  205. Curve.from_der(bad_der)
  206. self.assertIn("Unknown field type: (1, 2, 3)", str(e.exception))
  207. def test_decode_malformed_garbage_after_prime(self):
  208. curve_p = NIST256p.curve.p()
  209. bad_der = der.encode_sequence(
  210. der.encode_integer(1),
  211. der.encode_sequence(
  212. der.encode_oid(*PRIME_FIELD_OID),
  213. der.encode_integer(curve_p),
  214. der.encode_integer(1),
  215. ),
  216. der.encode_sequence(
  217. der.encode_octet_string(
  218. number_to_string(NIST256p.curve.a() % curve_p, curve_p)
  219. ),
  220. der.encode_octet_string(
  221. number_to_string(NIST256p.curve.b(), curve_p)
  222. ),
  223. ),
  224. der.encode_octet_string(
  225. NIST256p.generator.to_bytes("uncompressed")
  226. ),
  227. der.encode_integer(NIST256p.generator.order()),
  228. )
  229. with self.assertRaises(der.UnexpectedDER) as e:
  230. Curve.from_der(bad_der)
  231. self.assertIn("Prime-p element", str(e.exception))
  232. class TestCurveSearching(unittest.TestCase):
  233. def test_correct_name(self):
  234. c = curve_by_name("NIST256p")
  235. self.assertIs(c, NIST256p)
  236. def test_openssl_name(self):
  237. c = curve_by_name("prime256v1")
  238. self.assertIs(c, NIST256p)
  239. def test_unknown_curve(self):
  240. with self.assertRaises(UnknownCurveError) as e:
  241. curve_by_name("foo bar")
  242. self.assertIn(
  243. "name 'foo bar' unknown, only curves supported: "
  244. "['NIST192p', 'NIST224p'",
  245. str(e.exception),
  246. )
  247. def test_with_None_as_parameter(self):
  248. with self.assertRaises(UnknownCurveError) as e:
  249. curve_by_name(None)
  250. self.assertIn(
  251. "name None unknown, only curves supported: "
  252. "['NIST192p', 'NIST224p'",
  253. str(e.exception),
  254. )
  255. @pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves])
  256. def test_curve_params_encode_decode_named(curve):
  257. ret = Curve.from_der(curve.to_der("named_curve"))
  258. assert curve == ret
  259. @pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves])
  260. def test_curve_params_encode_decode_explicit(curve):
  261. if isinstance(curve.curve, CurveEdTw):
  262. with pytest.raises(UnknownCurveError):
  263. curve.to_der("explicit")
  264. else:
  265. ret = Curve.from_der(curve.to_der("explicit"))
  266. assert curve == ret
  267. @pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves])
  268. def test_curve_params_encode_decode_default(curve):
  269. ret = Curve.from_der(curve.to_der())
  270. assert curve == ret
  271. @pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves])
  272. def test_curve_params_encode_decode_explicit_compressed(curve):
  273. if isinstance(curve.curve, CurveEdTw):
  274. with pytest.raises(UnknownCurveError):
  275. curve.to_der("explicit", "compressed")
  276. else:
  277. ret = Curve.from_der(curve.to_der("explicit", "compressed"))
  278. assert curve == ret