test_authentication.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. # -*- coding: utf-8 -*-
  2. """ tests.test_authentication
  3. Unit tests for conda-content-trust/car/authentication.py
  4. as well as integration tests for the signing.py + authentication.py.
  5. Run the tests this way:
  6. pytest tests/test_authentication.py
  7. """
  8. # Python2 Compatibility
  9. from __future__ import absolute_import, division, print_function, unicode_literals
  10. # std libs
  11. import copy
  12. import os
  13. # dependencies
  14. import pytest
  15. import cryptography.exceptions
  16. # this codebase
  17. from conda_content_trust.authentication import *
  18. from conda_content_trust.metadata_construction import (
  19. gen_keys, gen_and_write_keys, # for new-key tests
  20. # build_repodata_verification_metadata
  21. )
  22. from conda_content_trust.common import (
  23. PrivateKey, PublicKey, keyfiles_to_bytes, keyfiles_to_keys,
  24. SignatureError, MetadataVerificationError)
  25. from conda_content_trust.signing import wrap_as_signable, sign_signable
  26. # Some REGRESSION test data.
  27. REG__KEYPAIR_NAME = 'keytest_old'
  28. REG__PRIVATE_BYTES = b'\xc9\xc2\x06\r~\r\x93al&T\x84\x0bI\x83\xd0\x02!\xd8\xb6\xb6\x9c\x85\x01\x07\xdat\xb4!h\xf97'
  29. REG__PUBLIC_BYTES = b"\x01=\xddqIb\x86m\x12\xba[\xae'?\x14\xd4\x8c\x89\xcf\x07s\xde\xe2\xdb\xf6\xd4V\x1eR\x1c\x83\xf7"
  30. REG__PUBLIC_HEX_ROOT = 'c8bd83b3bfc991face417d97b9c0db011b5d256476b602b92fec92849fc2b36c'
  31. REG__MESSAGE_THAT_WAS_SIGNED = b'123456\x067890'
  32. # Signature is over REG__MESSAGE_THAT_WAS_SIGNED using key REG__PRIVATE_BYTES.
  33. REG__SIGNATURE = b'\xb6\xda\x14\xa1\xedU\x9e\xbf\x01\xb3\xa9\x18\xc9\xb8\xbd\xccFM@\x87\x99\xe8\x98\x84C\xe4}9;\xa4\xe5\xfd\xcf\xdaau\x04\xf5\xcc\xc0\xe7O\x0f\xf0F\x91\xd3\xb8"\x7fD\x1dO)*\x1f?\xd7&\xd6\xd3\x1f\r\x0e'
  34. REG__SIGNATURE_HEX = 'b6da14a1ed559ebf01b3a918c9b8bdcc464d408799e8988443e47d393ba4e5fdcfda617504f5ccc0e74f0ff04691d3b8227f441d4f292a1f3fd726d6d31f0d0e'
  35. # REG__HASHED_VAL = b'string to hash\n'
  36. # REG__HASH_HEX = '73aec9a93f4beb41a9bad14b9d1398f60e78ccefd97e4eb7d3cf26ba71dbe0ce'
  37. # #REG__HASH_BYTES = b's\xae\xc9\xa9?K\xebA\xa9\xba\xd1K\x9d\x13\x98\xf6\x0ex\xcc\xef\xd9~N\xb7\xd3\xcf&\xbaq\xdb\xe0\xce'
  38. # REG__REPODATA_HASHMAP = {
  39. # "noarch/current_repodata.json": "908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe",
  40. # "noarch/repodata.json": "908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe",
  41. # "noarch/repodata_from_packages.json": "908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe",
  42. # "osx-64/current_repodata.json": "8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2",
  43. # "osx-64/repodata.json": "8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2",
  44. # "osx-64/repodata_from_packages.json": "8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2"
  45. # }
  46. REG__TEST_TIMESTAMP = '2019-10-01T00:00:00Z'
  47. REG__TEST_EXPIRY_DATE = '2025-01-01T10:30:00Z'
  48. # REG__EXPECTED_UNSIGNED_REPODATA_VERIFY = {
  49. # 'type': 'repodata_verify', 'timestamp': REG__TEST_TIMESTAMP,
  50. # 'metadata_spec_version': '0.0.5', 'expiration': REG__TEST_EXPIRY_DATE,
  51. # 'secured_files': {
  52. # 'noarch/current_repodata.json': '908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe',
  53. # 'noarch/repodata.json': '908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe',
  54. # 'noarch/repodata_from_packages.json': '908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe',
  55. # 'osx-64/current_repodata.json': '8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2',
  56. # 'osx-64/repodata.json': '8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2',
  57. # 'osx-64/repodata_from_packages.json': '8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2'}
  58. # }
  59. # REG__EXPECTED_REGSIGNED_REPODATA_VERIFY = {
  60. # # Re-sign this if its data changes: it's signed!
  61. # 'type': 'repodata_verify', 'timestamp': '2019-10-01T00:00:00Z',
  62. # 'metadata_spec_version': '0.0.5', 'expiration': '2025-01-01T10:30:00Z',
  63. # 'secured_files': {
  64. # 'noarch/current_repodata.json': '908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe',
  65. # 'noarch/repodata.json': '908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe',
  66. # 'noarch/repodata_from_packages.json': '908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe',
  67. # 'osx-64/current_repodata.json': '8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2',
  68. # 'osx-64/repodata.json': '8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2',
  69. # 'osx-64/repodata_from_packages.json': '8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2'}
  70. # }
  71. TEST_ROOT_MD_V1 = {
  72. "signatures": {
  73. "c8bd83b3bfc991face417d97b9c0db011b5d256476b602b92fec92849fc2b36c": {
  74. "other_headers": "04001608001d162104917adb684e2e9fb5ed4e59909ddd19a1268b62d005025f96ff1a",
  75. "signature": "9327c2c4907c964741924420c4c35eb01805c15ec2fe5cad17bc98c0c3daf03006fcafb332eaa543a1ed212fac05f227662d8617970afc6c919ee4b78bacb004"
  76. }
  77. },
  78. "signed": {
  79. "delegations": {
  80. "key_mgr": {
  81. "pubkeys": [
  82. "013ddd714962866d12ba5bae273f14d48c89cf0773dee2dbf6d4561e521c83f7"
  83. ],
  84. "threshold": 1
  85. },
  86. "root": {
  87. "pubkeys": [
  88. "c8bd83b3bfc991face417d97b9c0db011b5d256476b602b92fec92849fc2b36c"
  89. ],
  90. "threshold": 1
  91. }
  92. },
  93. "expiration": "2021-10-26T16:53:46Z",
  94. "metadata_spec_version": "0.6.0",
  95. "timestamp": "2020-10-26T16:53:46Z",
  96. "type": "root",
  97. "version": 1
  98. }
  99. }
  100. TEST_ROOT_MD_V2 = {
  101. "signatures": {
  102. "a59cea0987ee9046d68d2d011e919eb9278e3f478cca77f5204d65191ff8d7a5": {
  103. "other_headers": "04001608001d1621040a14b126c986f276831c7b04134f35b47db4364305025f96ff1b",
  104. "signature": "d406839499630a75350ba6f6c009aae173f15dd8c9be069c9b535ff77b6d624d6092487fe18e2c4f5c13b252a3ebe3f89ab15f4c52c66db752f8cbbfc6d96609"
  105. },
  106. "c8bd83b3bfc991face417d97b9c0db011b5d256476b602b92fec92849fc2b36c": {
  107. "other_headers": "04001608001d162104917adb684e2e9fb5ed4e59909ddd19a1268b62d005025f96ff1b",
  108. "signature": "f4c13d4456028778026639fcdc63ec7d6005e1e88f2dcfaf87afa3b89ce6a1ec8938af83fdc9d3d7045d0ebd648654c6af027daaf7164e014a8a53f373e9b906"
  109. }
  110. },
  111. "signed": {
  112. "delegations": {
  113. "key_mgr": {
  114. "pubkeys": [
  115. "013ddd714962866d12ba5bae273f14d48c89cf0773dee2dbf6d4561e521c83f7"
  116. ],
  117. "threshold": 1
  118. },
  119. "root": {
  120. "pubkeys": [
  121. "c8bd83b3bfc991face417d97b9c0db011b5d256476b602b92fec92849fc2b36c"
  122. ],
  123. "threshold": 1
  124. }
  125. },
  126. "expiration": "2021-10-26T16:53:46Z",
  127. "metadata_spec_version": "0.6.0",
  128. "timestamp": "2020-10-26T16:53:46Z",
  129. "type": "root",
  130. "version": 2
  131. }
  132. }
  133. # NOTE to dev:
  134. # test_authenticate was originally a long sequence of tests in a single
  135. # function. I pulled out most of it, and what remains is has to be compared
  136. # to the new tests to see if it's still useful.
  137. def test_wrap_sign_verify_signable():
  138. # Make a new keypair. Returns keys and writes keys to disk.
  139. # Then load it from disk and compare that to the return value. Exercise
  140. # some of the functions redundantly.
  141. generated_private, generated_public = gen_and_write_keys('keytest_new')
  142. loaded_new_private_bytes, loaded_new_public_bytes = keyfiles_to_bytes(
  143. 'keytest_new')
  144. loaded_new_private, loaded_new_public = keyfiles_to_keys('keytest_new')
  145. old_private = PrivateKey.from_bytes(REG__PRIVATE_BYTES)
  146. old_public = PublicKey.from_bytes(REG__PUBLIC_BYTES)
  147. assert generated_private.is_equivalent_to(loaded_new_private)
  148. assert generated_public.is_equivalent_to(loaded_new_public)
  149. assert loaded_new_private.is_equivalent_to(
  150. PrivateKey.from_bytes(loaded_new_private_bytes))
  151. assert loaded_new_public.is_equivalent_to(
  152. PublicKey.from_bytes(loaded_new_public_bytes))
  153. # Clean up a bit for the next tests.
  154. new_private = loaded_new_private
  155. new_public = loaded_new_public
  156. del (
  157. loaded_new_public, loaded_new_private,
  158. generated_private, generated_public,
  159. loaded_new_private_bytes, loaded_new_public_bytes)
  160. # Test wrapping, signing signables, and verifying signables.
  161. d = {'foo': 'bar', '1': 2}
  162. d_modified = {'foo': 'DOOM', '1': 2}
  163. signable_d = wrap_as_signable(d)
  164. assert is_a_signable(signable_d)
  165. sign_signable(signable_d, old_private)
  166. assert is_a_signable(signable_d)
  167. verify_signable(
  168. signable=signable_d,
  169. authorized_pub_keys=[old_public.to_hex()],
  170. threshold=1)
  171. # Expect failure this time due to bad format.
  172. try:
  173. verify_signable(
  174. signable=signable_d['signed'],
  175. authorized_pub_keys=[old_public.to_hex()],
  176. threshold=1)
  177. except TypeError:
  178. pass
  179. else:
  180. assert False, 'Failed to raise expected exception.'
  181. # Expect failure this time due to non-matching signature.
  182. try:
  183. modified_signable_d = copy.deepcopy(signable_d)
  184. modified_signable_d['signed'] = d_modified
  185. verify_signable(
  186. signable=modified_signable_d,
  187. authorized_pub_keys=[old_public.to_hex()],
  188. threshold=1)
  189. except SignatureError:
  190. pass
  191. else:
  192. assert False, 'Failed to raise expected exception.'
  193. # Clean up a bit.
  194. for fname in [
  195. 'keytest_new.pub', 'keytest_new.pri',
  196. 'keytest_old.pri', 'keytest_old.pub']:
  197. if os.path.exists(fname):
  198. os.remove(fname)
  199. # def test_repodata_verify_funcs():
  200. # # Test construction and verification of signed repodata_verify, including
  201. # # wrapping, signing the signable, and verifying the signables with a real
  202. # # example.
  203. # repodata_hashmap = {
  204. # "noarch/current_repodata.json":
  205. # "908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe",
  206. # "noarch/repodata.json":
  207. # "908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe",
  208. # "noarch/repodata_from_packages.json":
  209. # "908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe",
  210. # "osx-64/current_repodata.json":
  211. # "8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2",
  212. # "osx-64/repodata.json":
  213. # "8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2",
  214. # "osx-64/repodata_from_packages.json":
  215. # "8120fb07a6a8a280ffa2b89fb2fbb89484823d0b0357ff0cfa7c333352b2faa2"}
  216. # rd_v_md = build_repodata_verification_metadata(repodata_hashmap)
  217. # signable_rd_v_md = wrap_as_signable(rd_v_md)
  218. # assert is_a_signable(signable_rd_v_md)
  219. # sign_signable(signable_rd_v_md, old_private)
  220. # assert is_a_signable(signable_rd_v_md)
  221. # verify_signable(
  222. # signable=signable_rd_v_md,
  223. # authorized_pub_keys=[old_public.to_hex()],
  224. # threshold=1)
  225. # # Expect failure this time due to non-matching signature.
  226. # try:
  227. # modified_signable_rd_v_md = copy.deepcopy(signable_rd_v_md)
  228. # modified_signable_rd_v_md[
  229. # 'signed']['secured_files']['noarch/current_repodata.json'
  230. # ] = modified_signable_rd_v_md['signed']['secured_files'][
  231. # 'noarch/current_repodata.json'][:-1] + 'f' # TODO: Generalize test condition. (Also, un-ugly.)
  232. # verify_signable(
  233. # signable=modified_signable_rd_v_md,
  234. # authorized_pub_keys=[old_public.to_hex()],
  235. # threshold=1)
  236. # except SignatureError:
  237. # pass
  238. # else:
  239. # assert False, 'Failed to raise expected exception.'
  240. # # DEBUG: 💥💥💥💥 Dump the various bits and pieces for debugging.
  241. # # Remove this.
  242. # with open('_test_output__repodata_hashmap.json', 'wb') as fobj:
  243. # fobj.write(canonserialize(repodata_hashmap))
  244. # with open('_test_output__repodata_verify.json', 'wb') as fobj:
  245. # fobj.write(canonserialize(signable_rd_v_md))
  246. # # Additional regression test for a file produced by the indexer.
  247. # # This should come up as good.
  248. # verify_signable(
  249. # signable={
  250. # "signatures": {
  251. # "013ddd714962866d12ba5bae273f14d48c89cf0773dee2dbf6d4561e521c83f7": "740a426113cb83a62e58eb41fcd0b5f36691b0b18bffbe7eb3da30b5baf83f6c703a0fdb584599702470c74f55572a27cf9de250fc3afb723c43fef4dc778401"
  252. # },
  253. # "signed": {
  254. # "expiration": "2019-10-28T15:36:32Z",
  255. # "metadata_spec_version": "0.0.4",
  256. # "secured_files": {
  257. # "noarch/current_repodata.json": "908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe",
  258. # "noarch/repodata.json": "908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe",
  259. # "noarch/repodata_from_packages.json": "908724926552827ab58dfc0bccba92426cec9f1f483883da3ff0d8664e18c0fe",
  260. # "osx-64/current_repodata.json": "fc9268ea2b4add37e090b7f2b2c88b95c513cab445fb099e8631d8815a384ae4",
  261. # "osx-64/repodata.json": "fc9268ea2b4add37e090b7f2b2c88b95c513cab445fb099e8631d8815a384ae4",
  262. # "osx-64/repodata_from_packages.json": "fc9268ea2b4add37e090b7f2b2c88b95c513cab445fb099e8631d8815a384ae4"
  263. # },
  264. # "timestamp": "2019-09-27T15:36:32Z",
  265. # "type": "repodata_verify"
  266. # }
  267. # },
  268. # authorized_pub_keys=[old_public.to_hex()],
  269. # threshold=1)
  270. def test_sign_and_verify():
  271. """
  272. Tests functions:
  273. - sign
  274. - verify
  275. """
  276. # Generate new keys and construct key objects for old keys.
  277. new_private, new_public = gen_keys()
  278. old_private = PrivateKey.from_bytes(REG__PRIVATE_BYTES)
  279. old_public = PublicKey.from_bytes(REG__PUBLIC_BYTES)
  280. old_sig = old_private.sign(REG__MESSAGE_THAT_WAS_SIGNED)
  281. new_sig = new_private.sign(REG__MESSAGE_THAT_WAS_SIGNED)
  282. new_sig2 = new_private.sign(REG__MESSAGE_THAT_WAS_SIGNED)
  283. assert new_sig == new_sig2 # deterministic (obv not a thorough test)
  284. assert old_sig == REG__SIGNATURE # regression
  285. # Test verify()
  286. # Good signatures first.
  287. old_public.verify(REG__SIGNATURE, REG__MESSAGE_THAT_WAS_SIGNED)
  288. old_public.verify(old_sig, REG__MESSAGE_THAT_WAS_SIGNED)
  289. new_public.verify(new_sig, REG__MESSAGE_THAT_WAS_SIGNED)
  290. # Use wrong public key.
  291. wrong_pubkey_obj = PublicKey.from_hex(
  292. '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef')
  293. with pytest.raises(cryptography.exceptions.InvalidSignature):
  294. wrong_pubkey_obj.verify(REG__SIGNATURE, REG__MESSAGE_THAT_WAS_SIGNED)
  295. # Use bad data.
  296. with pytest.raises(cryptography.exceptions.InvalidSignature):
  297. old_public.verify(new_sig, REG__MESSAGE_THAT_WAS_SIGNED + b'a')
  298. with pytest.raises(cryptography.exceptions.InvalidSignature):
  299. new_public.verify(new_sig, REG__MESSAGE_THAT_WAS_SIGNED[0:-1])
  300. def test_verify_signature():
  301. verify_signature(
  302. REG__SIGNATURE_HEX,
  303. PublicKey.from_bytes(REG__PUBLIC_BYTES),
  304. REG__MESSAGE_THAT_WAS_SIGNED)
  305. # invalid signatures
  306. with pytest.raises(cryptography.exceptions.InvalidSignature):
  307. verify_signature(
  308. REG__SIGNATURE_HEX[:-6] + 'ffffff', # wrong value
  309. PublicKey.from_bytes(REG__PUBLIC_BYTES),
  310. REG__MESSAGE_THAT_WAS_SIGNED)
  311. with pytest.raises(TypeError):
  312. verify_signature(
  313. REG__SIGNATURE_HEX[:-1], # wrong length
  314. PublicKey.from_bytes(REG__PUBLIC_BYTES),
  315. REG__MESSAGE_THAT_WAS_SIGNED)
  316. with pytest.raises(TypeError):
  317. verify_signature(
  318. REG__SIGNATURE, # wrong type
  319. PublicKey.from_bytes(REG__PUBLIC_BYTES),
  320. REG__MESSAGE_THAT_WAS_SIGNED)
  321. # other bad args
  322. with pytest.raises(cryptography.exceptions.InvalidSignature):
  323. verify_signature(
  324. REG__SIGNATURE_HEX, # wrong type
  325. PublicKey.from_bytes(REG__PUBLIC_BYTES),
  326. REG__MESSAGE_THAT_WAS_SIGNED + b'\xc9') # altered message
  327. with pytest.raises(cryptography.exceptions.InvalidSignature):
  328. verify_signature(
  329. REG__SIGNATURE_HEX,
  330. PublicKey.from_bytes(REG__PUBLIC_BYTES[:-4] + b'0000'), # wrong key
  331. REG__MESSAGE_THAT_WAS_SIGNED)
  332. with pytest.raises(TypeError):
  333. verify_signature(
  334. REG__SIGNATURE_HEX,
  335. REG__PUBLIC_BYTES, # wrong type
  336. REG__MESSAGE_THAT_WAS_SIGNED)
  337. with pytest.raises(TypeError):
  338. verify_signature(
  339. REG__SIGNATURE_HEX,
  340. PublicKey.from_bytes(REG__PUBLIC_BYTES),
  341. {'this is not bytes': 1}) # wrong type
  342. # verify_root is also tested in test_root.py (but test_root.py expects GPG)
  343. def test_verify_root():
  344. """
  345. Tests conda_content_trust.authentication.verify_root
  346. """
  347. # Root chaining: normal test
  348. verify_root(TEST_ROOT_MD_V1, TEST_ROOT_MD_V2)
  349. # Now we tinker a bit to break stuff.
  350. root_v2_edited = copy.deepcopy(TEST_ROOT_MD_V2)
  351. # Can't verify root v10 using root v1 (chaining)
  352. with pytest.raises(MetadataVerificationError):
  353. root_v2_edited['signed']['version'] = 10
  354. verify_root(TEST_ROOT_MD_V1, root_v2_edited)
  355. # Reset.
  356. root_v2_edited['signed']['version'] = TEST_ROOT_MD_V2['signed']['version']
  357. # Bad signature, same keys, same contents
  358. # with pytest.raises(cryptography.exceptions.InvalidSignature):
  359. with pytest.raises(SignatureError):
  360. sig = root_v2_edited['signatures'][REG__PUBLIC_HEX_ROOT]['signature']
  361. sig = sig[:-6] + 'ffffff'
  362. root_v2_edited['signatures'][REG__PUBLIC_HEX_ROOT]['signature'] = sig
  363. verify_root(TEST_ROOT_MD_V1, root_v2_edited)
  364. # Reset.
  365. root_v2_edited['signatures'] = copy.deepcopy(TEST_ROOT_MD_V2['signatures'])
  366. # Not enough signatures from authorized keys:
  367. # Have one of the signatures claim to be from the wrong key.
  368. with pytest.raises(SignatureError):
  369. root_v2_edited['signatures'][REG__PUBLIC_HEX_ROOT[:-6] + 'ffffff'] \
  370. = root_v2_edited['signatures'][REG__PUBLIC_HEX_ROOT]
  371. del root_v2_edited['signatures'][REG__PUBLIC_HEX_ROOT]
  372. verify_root(TEST_ROOT_MD_V1, root_v2_edited)
  373. # Reset.
  374. root_v2_edited['signatures'] = copy.deepcopy(TEST_ROOT_MD_V2['signatures'])
  375. # Not enough signatures from authorized keys:
  376. # Change the trusted metadata such that we expect sigs from 3 distinct
  377. # authorized keys (and still provide only 2).
  378. with pytest.raises(SignatureError):
  379. root_v1_edited = copy.deepcopy(TEST_ROOT_MD_V1)
  380. root_v1_edited['signed']['delegations']['root']['threshold'] += 1
  381. verify_root(root_v1_edited, TEST_ROOT_MD_V2)
  382. # Reset.
  383. root_v1_edited['signed']['delegations']['root']['threshold'] -= 1
  384. # def test_verify_delegation():
  385. # """
  386. # Tests conda_content_trust.authentication.verify_delegation
  387. # """
  388. # raise NotImplementedError('verify_delegation requires unit tests.')