def test_verify_existing_root_md(): # It's important that we are able to verify root metadata without anything # except old root metadata, so in particular we don't want to need the # full GPG public key object. Ideally, we want only the Q value of the # key, but if we also need to retain the GPG key fingerprint (listed in the # signature itself), we can do that..... # with open('T_full_rmd.json', 'rb') as fobj: # signed_rmd = json.load(fobj) # # gpg_sig = signed_rmd['signatures'][ # 'bfbeb6554fca9558da7aa05c5e9952b7a1aa3995dede93f3bb89f0abecc7dc07'] # # canonical_signed_portion = common.canonserialize(signed_rmd['signed']) # # with open('T_gpg_key_obj.json', 'rb') as fobj: # gpg_key_obj = json.load(fobj) # q = gpg_key_obj['keyval']['public']['q'] # fingerprint = gpg_key_obj['keyid'] canonical_signed_portion = common.canonserialize(SAMPLE_ROOT_MD_CONTENT) # # First, try using securesystemslib's GPG signature verifier directly. # verified = securesystemslib.gpg.functions.verify_signature( # SAMPLE_GPG_SIG, # SAMPLE_GPG_KEY_OBJ, # <-- We don't want conda to have to provide this. # canonical_signed_portion) # assert verified # # Second, try it using my adapter, skipping a bit of ssl's process. # verified = root_signing.verify_gpg_sig_using_ssl( # SAMPLE_GPG_SIG, # SAMPLE_FINGERPRINT, # SAMPLE_KEYVAL, # canonical_signed_portion) # assert verified # Third, use internal code only. (This is what we're actually going to # use in conda.) # Verify using verify_gpg_signature. authentication.verify_gpg_signature( # authentication.verify_gpg_signature( SAMPLE_GPG_SIG, SAMPLE_KEYVAL, canonical_signed_portion) print('--TEST SUCCESS✅: GPG signature verification without using GPG or ' 'securesystemslib') # Verify using verify_signable. authentication.verify_signable(SAMPLE_SIGNED_ROOT_MD, [SAMPLE_KEYVAL], 1, gpg=True)
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