def test_root_gen_sign_verify(): # Integration test # Build a basic root metadata file with empty key_mgr delegation and one # root key, threshold 1, version 1. rmd = metadata_construction.build_root_metadata( root_version=1, root_pubkeys=[SAMPLE_KEYVAL], root_threshold=1, key_mgr_pubkeys=[], key_mgr_threshold=1) rmd = signing.wrap_as_signable(rmd) signed_portion = rmd['signed'] canonical_signed_portion = common.canonserialize(signed_portion) if not SSLIB_AVAILABLE: pytest.skip('--TEST SKIPPED⚠️ : Unable to perform GPG signing without ' 'securesystemslib and GPG.') return # gpg_key_obj = securesystemslib.gpg.functions.export_pubkey( # SAMPLE_FINGERPRINT) gpg_sig = root_signing.sign_via_gpg(canonical_signed_portion, SAMPLE_FINGERPRINT) signed_rmd = copy.deepcopy(rmd) signed_rmd['signatures'][SAMPLE_KEYVAL] = gpg_sig # # Dump working files # with open('T_gpg_sig.json', 'wb') as fobj: # fobj.write(common.canonserialize(gpg_sig)) # with open('T_gpg_key_obj.json', 'wb') as fobj: # fobj.write(common.canonserialize(gpg_key_obj)) # with open('T_canonical_sigless_md.json', 'wb') as fobj: # fobj.write(canonical_signed_portion) # with open('T_full_rmd.json', 'wb') as fobj: # fobj.write(common.canonserialize(signed_rmd)) # Verify using the SSL code and the expected pubkey object. # # (Purely as a test -- we wouldn't normally do this.) # verified = securesystemslib.gpg.functions.verify_signature( # gpg_sig, gpg_key_obj, canonical_signed_portion) # assert verified authentication.verify_gpg_signature(gpg_sig, SAMPLE_KEYVAL, canonical_signed_portion) print('--TEST SUCCESS✅: GPG signing (using GPG and securesystemslib) and ' 'GPG signature verification (using only cryptography)')
def create_root(self, keys): root_keys = keys["root"] root_pubkeys = [k["public"] for k in root_keys] key_mgr_pubkeys = [k["public"] for k in keys["key_mgr"]] root_version = 1 root_md = cct_metadata_construction.build_root_metadata( root_pubkeys=root_pubkeys[0:1], root_threshold=1, root_version=root_version, key_mgr_pubkeys=key_mgr_pubkeys, key_mgr_threshold=1, ) # Wrap the metadata in a signing envelope. root_md = cct_signing.wrap_as_signable(root_md) root_md_serialized_unsigned = cct_common.canonserialize(root_md) root_filepath = self.folder / f"{root_version}.root.json" print("Writing out: ", root_filepath) # Write unsigned sample root metadata. with open(root_filepath, "wb") as fout: fout.write(root_md_serialized_unsigned) # This overwrites the file with a signed version of the file. cct_root_signing.sign_root_metadata_via_gpg( root_filepath, root_keys[0]["fingerprint"]) # Load untrusted signed root metadata. signed_root_md = cct_common.load_metadata_from_file(root_filepath) cct_authentication.verify_signable(signed_root_md, root_pubkeys, 1, gpg=True) console.print("[green]Root metadata signed & verified!")
def demo_root_signing_and_verifying_and_chaining(): # Build sample root metadata. ('metadata' -> 'md') root_md = cct_metadata_construction.build_root_metadata( root_pubkeys=[ROOT_PUBKEY_HEX], root_threshold=1, root_version=1, key_mgr_pubkeys=[KEYMGR_PUBLIC_HEX], key_mgr_threshold=1) # Wrap the metadata in a signing envelope. root_md = cct_signing.wrap_as_signable(root_md) root_md_serialized_unsigned = cct_common.canonserialize(root_md) print('\n-- Unsigned root metadata version 1 generated.\n') # # This is the part of the data over which signatures are constructed. # root_md_serialized_portion_to_sign = cct_common.canonserialize( # root_md['signed']) # TODO: ✅ Format-validate constructed root metadata using checkformat # function. if not os.path.exists('demo'): os.mkdir('demo') # Write unsigned sample root metadata. with open(ROOT_FNAME_V1, 'wb') as fobj: fobj.write(root_md_serialized_unsigned) print('\n-- Unsigned root metadata version 1 written.\n') # Sign sample root metadata. junk = input_func( 'Preparing to request root signature. Please plug in your ' 'YubiKey and prepare to put in your user PIN in a GPG dialog box. ' ' When the YubiKey is plugged in and you are READY TO ENTER your ' 'pin, hit enter to begin.') # This overwrites the file with a signed version of the file. cct_root_signing.sign_root_metadata_via_gpg(ROOT_FNAME_V1, ROOT_PUBKEY_GPG_FINGERPRINT) cct_root_signing.sign_root_metadata_via_gpg(ROOT_FNAME_V1, ROOT_PUBKEY_GPG_FINGERPRINT) junk = input_func( '\n-- Root metadata v1 signed. Next: load signed root v1.\n') # Load untrusted signed root metadata. signed_root_md = cct_common.load_metadata_from_file(ROOT_FNAME_V1) junk = input_func( '\n-- Signed root metadata v1 loaded. Next: verify signed root v1\n') # Verify untrusted signed root metadata. (Normally, one uses the prior # version of root, but here we're bootstrapping for the demo. We'll verify # with a prior version lower down in this demo.) cct_authentication.verify_signable(signed_root_md, [ROOT_PUBKEY_HEX], 1, gpg=True) junk = input_func( '\n-- Root metadata v1 fully verified. Next: build root metadata v2.\n' ) # Build sample second version of root metadata. In this case, let's try # adding another authorized key and requiring signatures from both keys. root_md2 = cct_metadata_construction.build_root_metadata( root_pubkeys=[ROOT_PUBKEY_HEX, ROOT_PUBKEY_2_HEX], root_threshold=2, root_version=2, key_mgr_pubkeys=[KEYMGR_PUBLIC_HEX], key_mgr_threshold=1) # Wrap the version 2 metadata in a signing envelope, canonicalize it, and # serialize it to write to disk. root_md2 = cct_signing.wrap_as_signable(root_md2) root_md2 = cct_common.canonserialize(root_md2) # Write unsigned sample root metadata. with open(ROOT_FNAME_V2, 'wb') as fobj: fobj.write(root_md2) junk = input_func( '\n-- Unsigned root metadata version 2 generated and written. Next: sign root v2\n' ) # This overwrites the file with a signed version of the file. # We'll sign with both keys specified. cct_root_signing.sign_root_metadata_via_gpg(ROOT_FNAME_V2, ROOT_PUBKEY_GPG_FINGERPRINT) cct_root_signing.sign_root_metadata_via_gpg(ROOT_FNAME_V2, ROOT_PUBKEY_2_GPG_FINGERPRINT) junk = input_func( '\n-- Root metadata v2 signed. Next: load and verify signed root v2 based on root v1 (root chaining).\n' ) # Load the now-signed version from disk. signed_root_md2 = cct_common.load_metadata_from_file(ROOT_FNAME_V2) # Test root chaining (verifying v2 using v1) cct_authentication.verify_root(signed_root_md, signed_root_md2) print('\n-- Root metadata v2 fully verified based directly on Root ' 'metadata v1 (root chaining success)\n') print('\n-- Success. :)\n') # Build sample third version of root metadata. In this case, let's reduce # the number of required keys to one. root_md3 = cct_metadata_construction.build_root_metadata( root_pubkeys=[ROOT_PUBKEY_HEX, ROOT_PUBKEY_2_HEX], root_threshold=1, root_version=3, key_mgr_pubkeys=[KEYMGR_PUBLIC_HEX], key_mgr_threshold=1) # Wrap the version 2 metadata in a signing envelope, canonicalize it, and # serialize it to write to disk. root_md3 = cct_signing.wrap_as_signable(root_md3) root_md3 = cct_common.canonserialize(root_md3) # Write unsigned sample root metadata. with open(ROOT_FNAME_V3, 'wb') as fobj: fobj.write(root_md3) junk = input_func( '\n-- Unsigned root metadata version 2 generated and written. Next: sign root v2\n' ) # This overwrites the file with a signed version of the file. # We'll sign with both keys specified. cct_root_signing.sign_root_metadata_via_gpg(ROOT_FNAME_V3, ROOT_PUBKEY_GPG_FINGERPRINT) cct_root_signing.sign_root_metadata_via_gpg(ROOT_FNAME_V3, ROOT_PUBKEY_2_GPG_FINGERPRINT) junk = input_func( '\n-- Root metadata v2 signed. Next: load and verify signed root v2 based on root v1 (root chaining).\n' ) # Load the now-signed version from disk. signed_root_md3 = cct_common.load_metadata_from_file(ROOT_FNAME_V3) # Test root chaining (verifying v2 using v1) cct_authentication.verify_root(signed_root_md2, signed_root_md3) print('\n-- Root metadata v3 fully verified based directly on Root ' 'metadata v2 (root chaining success)\n') print('\n-- Success. :)\n') return signed_root_md, signed_root_md2, signed_root_md3