def test_import_rsa_wrong_format(self): """Try import wrongly formatted RSA key, raises exception. """ not_an_rsa = "not_an_rsa" with open(not_an_rsa, "w") as f: f.write(not_an_rsa) with self.assertRaises(securesystemslib.exceptions.FormatError): import_rsa_key_from_file(not_an_rsa)
def test_create_and_import_encrypted_rsa_no_password(self): """Try import encrypted RSA key without or wrong pw, raises exception. """ name = "key3" password = "******" bits = 3072 generate_and_write_rsa_keypair(name, bits, password) with self.assertRaises(securesystemslib.exceptions.CryptoError): import_rsa_key_from_file(name) with self.assertRaises(securesystemslib.exceptions.CryptoError): import_rsa_key_from_file(name, "wrong-password")
def test_create_and_import_rsa(self): """Create RS key and import private and public key separately. """ name = "key1" generate_and_write_rsa_keypair(name) private_key = import_rsa_key_from_file(name) public_key = import_rsa_key_from_file(name + ".pub") securesystemslib.formats.KEY_SCHEMA.check_match(private_key) self.assertTrue(private_key["keyval"].get("private")) self.assertTrue( securesystemslib.formats.PUBLIC_KEY_SCHEMA.matches(public_key))
def test_create_and_import_encrypted_rsa_nondefault_length(self): name = "key_encrypted_2" password = "******" bits = 2048 generate_and_write_rsa_keypair(name, bits, password) private_key = import_rsa_key_from_file(name, password) public_key = import_rsa_key_from_file(name + ".pub") securesystemslib.formats.KEY_SCHEMA.check_match(private_key) self.assertTrue(private_key["keyval"].get("private")) self.assertTrue( securesystemslib.formats.PUBLIC_KEY_SCHEMA.matches(public_key))
def test_create_and_import_encrypted_rsa(self): """Create ecrypted RSA key and import private and public key separately.""" name = "key_encrypted" password = "******" bits = 3072 generate_and_write_rsa_keypair(name, bits, password) private_key = import_rsa_key_from_file(name, password) public_key = import_rsa_key_from_file(name + ".pub") securesystemslib.formats.KEY_SCHEMA.check_match(private_key) self.assertTrue(private_key["keyval"].get("private")) self.assertTrue( securesystemslib.formats.PUBLIC_KEY_SCHEMA.matches(public_key))
def setUpClass(self): """Creates and changes into temporary directory. Copies demo files to temp dir... - owner/functionary key pairs - *.link metadata files - layout template (not signed, no expiration date) - final product ...and dumps various layouts for different test scenarios """ # Backup original cwd self.working_dir = os.getcwd() # Find demo files demo_files = os.path.join(os.path.dirname(os.path.realpath(__file__)), "demo_files") # find where the scripts directory is located. scripts_directory = os.path.join( os.path.dirname(os.path.realpath(__file__)), "scripts") # Create and change into temporary directory self.test_dir = os.path.realpath(tempfile.mkdtemp()) os.chdir(self.test_dir) # Copy demo files to temp dir for file in os.listdir(demo_files): shutil.copy(os.path.join(demo_files, file), self.test_dir) shutil.copytree(scripts_directory, 'scripts') # Load layout template layout_template = Metablock.load("demo.layout.template") # Store layout paths to be used in tests self.layout_single_signed_path = "single-signed.layout" self.layout_double_signed_path = "double-signed.layout" # Import layout signing keys alice = import_rsa_key_from_file("alice") bob = import_rsa_key_from_file("bob") self.alice_path = "alice.pub" self.bob_path = "bob.pub" # dump a single signed layout layout_template.sign(alice) layout_template.dump(self.layout_single_signed_path) # dump a double signed layout layout_template.sign(bob) layout_template.dump(self.layout_double_signed_path)
def setUpClass(self): # Create layout with one inspection self.layout = Layout.read({ "_type": "layout", "inspect": [], "steps": [{ "name": "run-command", "expected_command": ["{EDITOR}"], }] }) super(Test_SubstituteOnVerify, self).setUpClass() # Find demo files demo_files = os.path.join(os.path.dirname(os.path.realpath(__file__)), "demo_files") # Copy demo files to temp dir for file in os.listdir(demo_files): shutil.copy(os.path.join(demo_files, file), self.test_dir) # load alice's key self.alice = import_rsa_key_from_file("alice") self.alice_pub_dict = import_public_keys_from_files_as_dict( ["alice.pub"])
def setUpClass(self): # Create layout with one inspection self.layout = Layout.read({ "_type": "layout", "inspect": [], "steps": [{ "name": "run-command", "expected_command": ["{EDITOR}"], }] }) # Backup original cwd self.working_dir = os.getcwd() # Find demo files demo_files = os.path.join(os.path.dirname(os.path.realpath(__file__)), "demo_files") # Create and change into temporary directory self.test_dir = os.path.realpath(tempfile.mkdtemp()) os.chdir(self.test_dir) # Copy demo files to temp dir for file in os.listdir(demo_files): shutil.copy(os.path.join(demo_files, file), self.test_dir) # load alice's key self.alice = import_rsa_key_from_file("alice") self.alice_pub_dict = import_public_keys_from_files_as_dict( ["alice.pub"])
def update_link_metadata(checks, core_workflow=True): root = get_root() ensure_dir_exists(path_join(root, LINK_DIR)) # Sign only what affects each wheel products = [] for check in checks: products.append(path_join(check, 'datadog_checks')) products.append(path_join(check, 'setup.py')) if core_workflow: key_id = get_key_id(GPG_COMMAND) # Find this latest signed link metadata file on disk. # NOTE: in-toto currently uses the first 8 characters of the signing keyId. key_id_prefix = key_id[:8].lower() tag_link = f'{STEP_NAME}.{key_id_prefix}.link' options = {'gpg_keyid': key_id} else: signing_key = util.import_rsa_key_from_file( os.getenv('IN_TOTO_SIGNING_KEY_PATH'), os.getenv('IN_TOTO_SIGNING_KEY_PASSWORD')) tag_link = f'{os.getenv("IN_TOTO_SIGNER")}.link' options = {'signing_key': signing_key} # Final location of metadata file. metadata_file = path_join(LINK_DIR, tag_link) with chdir(root): # We should ignore products untracked and ignored by git. run_in_toto(products, **options) # Check whether each signed product is being tracked AND ignored by git. # NOTE: We have to check now *AFTER* signing the tag link file, so that # we can check against the actual complete list of products. with open(tag_link) as tag_json: tag = json.load(tag_json) products = tag['signed']['products'] for product in products: # If NOT tracked... if not tracked_by_git(product): # First, delete the tag link off disk so as not to pollute. os.remove(tag_link) # AND NOT ignored, then it most likely means the developer # forgot to add the file to git. if not ignored_by_git(product): raise NeitherTrackedNorIgnoredFileException(product) # AND ignored, then it most likely means that incorrectly # recorded with in-toto files ignored by git. else: raise UntrackedButIgnoredFileException(product) # Move it to the expected location. shutil.move(tag_link, metadata_file) return (metadata_file, )
def main(): args = parse_arguments() # configure our instance of the grafeas api swagger_client.configuration.host = args.target api_instance = swagger_client.GrafeasApi() project_id = args.project_id try: # Create and return an unsigned link (not dumping to disk) link = runlib.in_toto_run(args.name, args.materials, args.products, args.link_cmd) # Now sign the link with the passed key key = util.import_rsa_key_from_file(args.key) link.sign(key) except Exception as e: print("Exception when calling in-toto runlib: {}".format(e)) sys.exit(1) # Create an occurrence from the link link_dict = attr.asdict(link) # We need to cast return-value to string or else parsing breaks mysteriously link_dict["signed"]["byproducts"]["return-value"] = \ str(link_dict["signed"]["byproducts"]["return-value"]) # Create the in-toto link extended occurrence metadata signable = swagger_client.LinkSignable(**(link_dict["signed"])) grafeas_link = swagger_client.LinkMetadata(signable, link.signatures) # Create the occurrence object that is posted to the server occurrence = swagger_client.Occurrence() # Occurrences/links use the step name + signing keyid as id # There can be multiple occurrences per note (links per step) occurrence_id = "{}-{}".format(args.name, link.signatures[0]["keyid"][:8]) occurrence_name = "projects/{}/occurrences/{}".format( project_id, occurrence_id) # Notes/steps only use the step name as id note_name = "projects/{}/notes/{}".format(project_id, args.name) occurrence.name = occurrence_name occurrence.note_name = note_name occurrence.link_metadata = grafeas_link try: api_response = api_instance.create_occurrence(project_id, occurrence=occurrence) pprint(api_response) except ApiException as e: print( "Exception when calling GrafeasApi->create_occurrence: {}".format( e)) sys.exit(1)
def main(): key_owner = import_rsa_key_from_file("dependency_owner") key_developer = import_rsa_key_from_file("../developer/developer.pub") key_reviewer = import_rsa_key_from_file("../reviewer/reviewer.pub") layout = Layout.read({ "_type": "layout", "keys": { key_developer["keyid"]: key_developer, key_reviewer["keyid"]: key_reviewer, }, "steps": [{ "name": "dependency-develop", "expected_materials": [], "expected_products": [ ["CREATE", "../dependency/demo.py"], ["DISALLOW", "*"] ], "pubkeys": [key_developer["keyid"]], "expected_command": [], "threshold": 1, },{ "name": "dependency-code-review", "expected_materials": [ ["MATCH", "../dependency/demo.py", "WITH", "PRODUCTS", "FROM", "dependency-develop"], ["DISALLOW", "*"] ], "expected_products": [ ["ALLOW", "../dependency/demo.py"], ["DISALLOW", "*"] ], "pubkeys": [key_reviewer["keyid"]], "expected_command": [], "threshold": 1, }, ], "inspect": [], }) metadata = Metablock(signed=layout) # Sign and dump layout to "root.layout" metadata.sign(key_owner) metadata.dump("../metadata_dependency/root.layout")
def setUpClass(self): """Creates and changes into temporary directory and prepares two layouts. The superlayout, which has one step and its sublayout, which is the usual demo layout (write code, package, inspect tar). """ # Backup original cwd self.working_dir = os.getcwd() # Find demo files demo_files = os.path.join(os.path.dirname(os.path.realpath(__file__)), "demo_files") # Create and change into temporary directory self.test_dir = os.path.realpath(tempfile.mkdtemp()) os.chdir(self.test_dir) # Copy demo files to temp dir for file in os.listdir(demo_files): shutil.copy(os.path.join(demo_files, file), self.test_dir) # Import sub layout signing (private) and verifying (public) keys alice = import_rsa_key_from_file("alice") alice_pub = import_rsa_key_from_file("alice.pub") # Copy, sign and dump sub layout as link from template layout_template = Metablock.load("demo.layout.template") sub_layout = copy.deepcopy(layout_template) sub_layout_name = "sub_layout" sub_layout_path = FILENAME_FORMAT.format(step_name=sub_layout_name, keyid=alice_pub["keyid"]) sub_layout.sign(alice) sub_layout.dump(sub_layout_path) # Create super layout that has only one step, the sublayout self.super_layout = Layout() self.super_layout.keys[alice_pub["keyid"]] = alice_pub sub_layout_step = Step(name=sub_layout_name, pubkeys=[alice_pub["keyid"]]) self.super_layout.steps.append(sub_layout_step) # Load the super layout links (i.e. the sublayout) self.super_layout_links = load_links_for_layout(self.super_layout)
def setUpClass(self): """Creates and changes into temporary directory. Copies demo files to temp dir... - owner/functionary key pairs - *.link metadata files - layout template (not signed, no expiration date) - final product ...and dumps layout for test scenario """ # Find demo files demo_files = os.path.join(os.path.dirname(os.path.realpath(__file__)), "demo_files") scripts_directory = os.path.join( os.path.dirname(os.path.realpath(__file__)), "scripts") self.set_up_test_dir() # Copy demo files to temp dir for fn in os.listdir(demo_files): shutil.copy(os.path.join(demo_files, fn), self.test_dir) shutil.copytree(scripts_directory, 'scripts') # Load layout template layout_template = Metablock.load("demo.layout.template") # Store layout paths to be used in tests self.layout_double_signed_path = "double-signed.layout" # Import layout signing keys alice = import_rsa_key_from_file("alice") danny = import_ed25519_privatekey_from_file("danny") self.alice_path = "alice.pub" self.danny_path = "danny.pub" # dump a double signed layout layout_template.sign(alice) layout_template.sign(danny) layout_template.dump(self.layout_double_signed_path)
def main(): # Load Niels's private key to later sign the layout key_niels = import_rsa_key_from_file("niels") # Fetch and load aimee's and noud's public keys # to specify that they are authorized to perform certain step in the layout key_aimee = import_rsa_key_from_file("../functionary_aimee/aimee.pub") key_noud = import_rsa_key_from_file("../functionary_noud/noud.pub") layout = Layout.read({ "_type": "layout", "keys": { key_aimee["keyid"]: key_aimee, key_noud["keyid"]: key_noud, }, "steps": [{ "name": "create", "expected_materials": [], "expected_products": [["CREATE", "app/Program.cs"], ["DISALLOW", "*"]], "pubkeys": [key_aimee["keyid"]], "expected_command": [ "dotnet", "new", "console", "-n", "app" ], "threshold": 1, },{ "name": "publish", "expected_materials": [ ["MATCH", "app/Program.cs", "WITH", "PRODUCTS", "FROM", "create"], ["DISALLOW", "*"], ], "expected_products": [["CREATE", "published/app"], ["CREATE", "published/app.*"], ["DISALLOW", "*"]], "pubkeys": [key_noud["keyid"]], "expected_command": [ "dotnet", "publish", "-o", "published", "app" ], "threshold": 1, },{ "name": "package", "expected_materials": [ ["MATCH", "published/*", "WITH", "PRODUCTS", "FROM", "publish"], ["DISALLOW", "*"], ], "expected_products": [ ["CREATE", "published.tar.gz"], ["DISALLOW", "*"], ], "pubkeys": [key_noud["keyid"]], "expected_command": [ "tar", "-zcvf", "published.tar.gz", "published", ], "threshold": 1, }], "inspect": [{ "name": "untar", "expected_materials": [ ["MATCH", "published.tar.gz", "WITH", "PRODUCTS", "FROM", "package"], # FIXME: If the routine running inspections would gather the # materials/products to record from the rules we wouldn't have to # ALLOW other files that we aren't interested in. ["ALLOW", ".keep"], ["ALLOW", "niels.pub"], ["ALLOW", "root.layout"], ["DISALLOW", "*"] ], "expected_products": [ ["MATCH", "published/*", "WITH", "PRODUCTS", "FROM", "publish"], # FIXME: See expected_materials above ["ALLOW", "published/app.*"], ["ALLOW", "published.tar.gz"], ["ALLOW", ".keep"], ["ALLOW", "niels.pub"], ["ALLOW", "root.layout"], ["DISALLOW", "*"] ], "run": [ "tar", "xzf", "published.tar.gz", ] }], }) metadata = Metablock(signed=layout) # Sign and dump layout to "root.layout" metadata.sign(key_niels) metadata.dump("root.layout")
#!/usr/bin/python from in_toto.models.layout import Layout, Step from in_toto.models.metadata import Metablock from in_toto.util import generate_and_write_rsa_keypair, import_rsa_key_from_file generate_and_write_rsa_keypair("build_key") build_key = import_rsa_key_from_file("build_key.pub") layout = Layout() build = Step(name="build") build.expected_materials.append(['ALLOW', 'package.json']) build.expected_materials.append(['ALLOW', 'index.js']) build.expected_command = ['npm', 'install'] layout.steps.append(build) layout.add_functionary_key(build_key) build.pubkeys.append(build_key['keyid']) generate_and_write_rsa_keypair("root_key") root_key = import_rsa_key_from_file("root_key") metablock = Metablock(signed=layout) metablock.sign(root_key) metablock.dump("root.layout")
def setUpClass(self): """Creates and changes into temporary directory. Copies demo files to temp dir... - owner/functionary key pairs - *.link metadata files - layout template (not signed, no expiration date) - final product ...and dumps various layouts for different test scenarios """ # Backup original cwd self.working_dir = os.getcwd() # Find demo files demo_files = os.path.join(os.path.dirname(os.path.realpath(__file__)), "demo_files") # Create and change into temporary directory self.test_dir = os.path.realpath(tempfile.mkdtemp()) os.chdir(self.test_dir) # Copy demo files to temp dir for file in os.listdir(demo_files): shutil.copy(os.path.join(demo_files, file), self.test_dir) # Load layout template layout_template = Metablock.load("demo.layout.template") # Store various layout paths to be used in tests self.layout_single_signed_path = "single-signed.layout" self.layout_double_signed_path = "double-signed.layout" self.layout_bad_sig = "bad-sig.layout" self.layout_expired_path = "expired.layout" self.layout_failing_step_rule_path = "failing-step-rule.layout" self.layout_failing_inspection_rule_path = "failing-inspection-rule.layout" self.layout_failing_inspection_retval = "failing-inspection-retval.layout" # Import layout signing keys alice = import_rsa_key_from_file("alice") bob = import_rsa_key_from_file("bob") self.alice_path = "alice.pub" self.bob_path = "bob.pub" # dump single signed layout layout = copy.deepcopy(layout_template) layout.sign(alice) layout.dump(self.layout_single_signed_path) # dump double signed layout layout = copy.deepcopy(layout_template) layout.sign(alice) layout.sign(bob) layout.dump(self.layout_double_signed_path) # dump layout with bad signature layout = copy.deepcopy(layout_template) layout.sign(alice) layout.signed.readme = "this breaks the signature" layout.dump(self.layout_bad_sig) # dump expired layout layout = copy.deepcopy(layout_template) layout.signed.expires = ( datetime.today() + relativedelta(months=-1)).strftime("%Y-%m-%dT%H:%M:%SZ") layout.sign(alice) layout.dump(self.layout_expired_path) # dump layout with failing step rule layout = copy.deepcopy(layout_template) layout.signed.steps[0].expected_products.insert(0, ["MODIFY", "*"]) layout.sign(alice) layout.dump(self.layout_failing_step_rule_path) # dump layout with failing inspection rule layout = copy.deepcopy(layout_template) layout.signed.inspect[0].expected_materials.insert(0, ["MODIFY", "*"]) layout.sign(alice) layout.dump(self.layout_failing_inspection_rule_path) # dump layout with failing inspection retval layout = copy.deepcopy(layout_template) layout.signed.inspect[0].run = ["expr", "1", "/", "0"] layout.sign(alice) layout.dump(self.layout_failing_inspection_retval)
def main(): # Load Alice's private key to later sign the layout key_alice = import_rsa_key_from_file("alice") # Fetch and load Bob's and Carl's public keys # to specify that they are authorized to perform certain step in the layout key_bob = import_rsa_key_from_file("../functionary_bob/bob.pub") key_carl = import_rsa_key_from_file("../functionary_carl/carl.pub") layout = Layout.read({ "_type": "layout", "keys": { key_bob["keyid"]: key_bob, key_carl["keyid"]: key_carl, }, "steps": [ { "name": "clone", "material_matchrules": [], "product_matchrules": [["CREATE", "demo-project/foo.py"]], "pubkeys": [key_bob["keyid"]], "expected_command": "git clone https://github.com/in-toto/demo-project.git", "threshold": 1, }, { "name": "update-version", "material_matchrules": [[ "MATCH", "demo-project/*", "WITH", "PRODUCTS", "FROM", "clone" ]], # FIXME: CREATE is more like an allow here, is fixed in next version "product_matchrules": [["ALLOW", "demo-project/foo.py"]], "pubkeys": [key_bob["keyid"]], "expected_command": "", "threshold": 1, }, { "name": "package", "material_matchrules": [ [ "MATCH", "demo-project/*", "WITH", "PRODUCTS", "FROM", "update-version" ], ], "product_matchrules": [ ["CREATE", "demo-project.tar.gz"], ], "pubkeys": [key_carl["keyid"]], "expected_command": "tar --exclude '.git' -zcvf demo-project.tar.gz demo-project", "threshold": 1, } ], "inspect": [{ "name": "untar", "material_matchrules": [ [ "MATCH", "demo-project.tar.gz", "WITH", "PRODUCTS", "FROM", "package" ], # FIXME: If the routine running inspections would gather the # materials/products to record from the rules we wouldn't have to # ALLOW other files that we aren't interested in. ["ALLOW", ".keep"], ["ALLOW", "alice.pub"], ["ALLOW", "root.layout"], ], "product_matchrules": [ [ "MATCH", "demo-project/foo.py", "WITH", "PRODUCTS", "FROM", "update-version" ], # FIXME: See material_matchrules above ["ALLOW", "demo-project/.git/*"], ["ALLOW", "demo-project.tar.gz"], ["ALLOW", ".keep"], ["ALLOW", "alice.pub"], ["ALLOW", "root.layout"], ], "run": "tar xzf demo-project.tar.gz", }], "signatures": [] }) # Sign and dump layout to "layout.root" layout.sign(key_alice) layout.dump()
#!/usr/bin/python from in_toto.models.layout import Layout, Step from in_toto.models.metadata import Metablock from in_toto.util import generate_and_write_rsa_keypair, import_rsa_key_from_file layout = Layout() build = Step(name="build") build.expected_materials.append(['ALLOW', 'src/*']) build.expected_products.append(['CREATE', 'foo']) analyze = Step(name="analyze") analyze.expected_materials.append( ['MATCH', 'foo', 'WITH', 'PRODUCTS', 'FROM', 'build']) layout.steps.append(build) layout.steps.append(analyze) generate_and_write_rsa_keypair("root_key") root_key = import_rsa_key_from_file("root_key") metablock = Metablock(signed=layout) metablock.sign(root_key) metablock.dump("root.layout")
def test_import_non_existing_rsa(self): """Try import non-existing RSA key, raises exception. """ with self.assertRaises(IOError): import_rsa_key_from_file("key-does-not-exist")
def main(): # Load Alice's private key to later sign the layout key_alice = import_rsa_key_from_file("alice") # Fetch and load Bob's and Carl's public keys # to specify that they are authorized to perform certain step in the layout key_bob = import_rsa_key_from_file("../functionary_bob/bob.pub") key_carl = import_rsa_key_from_file("../functionary_carl/carl.pub") layout = Layout.read({ "_type": "layout", "keys": { key_bob["keyid"]: key_bob, key_carl["keyid"]: key_carl, }, "steps": [{ "name": "clone", "expected_materials": [], "expected_products": [["CREATE", "demo-project/foo.py"], ["DISALLOW", "*"]], "pubkeys": [key_bob["keyid"]], "expected_command": "git clone https://github.com/in-toto/demo-project.git", "threshold": 1, }, { "name": "update-version", "expected_materials": [["MATCH", "demo-project/*", "WITH", "PRODUCTS", "FROM", "clone"], ["DISALLOW", "*"]], "expected_products": [["ALLOW", "demo-project/foo.py"], ["DISALLOW", "*"]], "pubkeys": [key_bob["keyid"]], "expected_command": "", "threshold": 1, }, { "name": "package", "expected_materials": [ [ "MATCH", "demo-project/*", "WITH", "PRODUCTS", "FROM", "update-version" ], ["DISALLOW", "*"], ], "expected_products": [ ["CREATE", "demo-project.tar.gz"], ["DISALLOW", "*"], ], "pubkeys": [key_carl["keyid"]], "expected_command": "tar --exclude '.git' -zcvf demo-project.tar.gz demo-project", "threshold": 1, }], "inspect": [{ "name": "untar", "expected_materials": [ [ "MATCH", "demo-project.tar.gz", "WITH", "PRODUCTS", "FROM", "package" ], # FIXME: If the routine running inspections would gather the # materials/products to record from the rules we wouldn't have to # ALLOW other files that we aren't interested in. ["ALLOW", ".keep"], ["ALLOW", "alice.pub"], ["ALLOW", "root.layout"], ["DISALLOW", "*"] ], "expected_products": [ [ "MATCH", "demo-project/foo.py", "WITH", "PRODUCTS", "FROM", "update-version" ], # FIXME: See expected_materials above ["ALLOW", "demo-project/.git/*"], ["ALLOW", "demo-project.tar.gz"], ["ALLOW", ".keep"], ["ALLOW", "alice.pub"], ["ALLOW", "root.layout"], ["DISALLOW", "*"] ], "run": "tar xzf demo-project.tar.gz", }], }) metadata = Metablock(signed=layout) # Sign and dump layout to "root.layout" metadata.sign(key_alice) metadata.dump("root.layout") if in_toto.settings.VERBOSE: log.info("--Begin printing layout metadata--") log.info(Layout.display(layout)) log.info("--End printing layout metadata--")
def main(): # Load Alice's private key to later sign the layout key_alice = import_rsa_key_from_file("alice") # Fetch and load Bob's and Carl's public keys # to specify that they are authorized to perform certain step in the layout key_bob = import_rsa_key_from_file("../functionary_bob/bob.pub") key_carl = import_rsa_key_from_file("../functionary_carl/carl.pub") layout = Layout.read({ "signed": { "_type": "layout", "keys": { key_bob["keyid"]: key_bob, key_carl["keyid"]: key_carl, }, "steps": [{ "name": "setup-project", "expected_materials": [], "expected_products": [["CREATE", "project.meta"], ["CREATE", "package.meta"]], "pubkeys": [key_bob["keyid"]], "expected_command": "", "threshold": 1, }, { "name": "clone", "expected_materials": [], "expected_products": [["CREATE", "connman/_service"], ["CREATE", "connman/connman-1.30.tar.gz"], ["CREATE", "connman/connman-1.30.tar.sign"], ["CREATE", "connman/connman-rpmlintrc"], ["CREATE", "connman/connman.changes"], ["CREATE", "connman/connman.keyring"], ["CREATE", "connman/connman.spec"]], "pubkeys": [key_bob["keyid"]], "expected_command": "", "threshold": 1, }, { "name": "update-changelog", "expected_materials": [[ "MATCH", "connman/connman.changes", "WITH", "PRODUCTS", "FROM", "clone" ]], "expected_products": [["ALLOW", "connman/connman.changes"]], "pubkeys": [key_bob["keyid"]], "expected_command": "", "threshold": 1, }, { "name": "test", "expected_materials": [], "expected_products": [], "pubkeys": [key_carl["keyid"]], "expected_command": "osc build openSUSE_Factory x86_64 connman/connman.spec", "threshold": 1, }, { "name": "package", "expected_materials": [ [ "MATCH", "connman/_service", "WITH", "PRODUCTS", "FROM", "clone" ], [ "MATCH", "connman/connman-1.30.tar.gz", "WITH", "PRODUCTS", "FROM", "clone" ], [ "MATCH", "connman/connman-1.30.tar.sign", "WITH", "PRODUCTS", "FROM", "clone" ], [ "MATCH", "connman/connman-rpmlintrc", "WITH", "PRODUCTS", "FROM", "clone" ], [ "MATCH", "connman/connman.changes", "WITH", "PRODUCTS", "FROM", "update-changelog" ], [ "MATCH", "connman/connman.keyring", "WITH", "PRODUCTS", "FROM", "clone" ], [ "MATCH", "connman/connman.spec", "WITH", "PRODUCTS", "FROM", "clone" ], ], "expected_products": [ ["CREATE", "connman-1.30-1.1.src.rpm"], ], "pubkeys": [key_carl["keyid"]], "expected_command": "", "threshold": 1, }], "inspect": [ { "name": "unpack", "expected_materials": [ [ "MATCH", "connman-1.30-1.1.src.rpm", "WITH", "PRODUCTS", "FROM", "package" ], # FIXME: If the routine running inspections would gather the # materials/products to record from the rules we wouldn't have to # ALLOW other files that we aren't interested in. ["ALLOW", ".keep"], ["ALLOW", "alice.pub"], ["ALLOW", "verify-signature.sh"], ["ALLOW", "root.layout"], ], "expected_products": [ [ "MATCH", "connman-1.30-1.1.src.rpm", "WITH", "PRODUCTS", "FROM", "package" ], [ "MATCH", "connman-1.30.tar.gz", "WITH", "PRODUCTS", "IN", "connman", "FROM", "clone" ], [ "MATCH", "_service", "WITH", "PRODUCTS", "IN", "connman", "FROM", "clone" ], [ "MATCH", "connman-1.30.tar.sign", "WITH", "PRODUCTS", "IN", "connman", "FROM", "clone" ], [ "MATCH", "connman-rpmlintrc", "WITH", "PRODUCTS", "IN", "connman", "FROM", "clone" ], [ "MATCH", "connman.changes", "WITH", "PRODUCTS", "IN", "connman", "FROM", "update-changelog" ], [ "MATCH", "connman.keyring", "WITH", "PRODUCTS", "IN", "connman", "FROM", "clone" ], # FIXME: hash doesn't match for this file because connman.spec in # rpm has changelog appended to it and release number incremented. ["ALLOW", "connman.spec"], ["ALLOW", ".keep"], ["ALLOW", "alice.pub"], ["ALLOW", "verify-signature.sh"], ["ALLOW", "root.layout"], ], "run": "unrpm connman-1.30-1.1.src.rpm", }, { "name": "verify-signature", "expected_materials": [["ALLOW", "*"]], "expected_products": [["ALLOW", "*"]], "run": "./verify-signature.sh", } ], }, "signatures": [] }) # Sign and dump layout to "layout.root" layout.sign(key_alice) layout.dump()
#!/usr/bin/python from in_toto.models.layout import Layout, Step from in_toto.models.metadata import Metablock from in_toto.util import generate_and_write_rsa_keypair, import_rsa_key_from_file # generate root key (project owner key) generate_and_write_rsa_keypair("root_key") root_key = import_rsa_key_from_file("root_key") # Generate two functionary keys generate_and_write_rsa_keypair("build_key") generate_and_write_rsa_keypair("analyze_key") build_key = import_rsa_key_from_file("build_key.pub") analyze_key = import_rsa_key_from_file("analyze_key.pub") # create a layout layout = Layout() # create the bulid step and add restrictions build = Step(name='build') build.expected_materials.append(["ALLOW", "src/*"]) build.expected_products.append(["CREATE", "foo"]) build.expected_command = ['gcc', '-o foo', 'src/*'] build.pubkeys.append(build_key['keyid']) # create the analyze step and add restrictions analyze = Step(name='analyze') analyze.expected_materials.append( ['MATCH', 'foo', 'WITH', 'PRODUCTS', 'FROM', 'build']) analyze.expected_command = ['valgrind', './foo']
def main(): key_owner = import_rsa_key_from_file("target_owner") key_dependency_owner = import_rsa_key_from_file("dependency_owner.pub") key_developer = import_rsa_key_from_file("../developer/developer.pub") key_reviewer = import_rsa_key_from_file("../reviewer/reviewer.pub") key_xray = import_rsa_key_from_file("../xray/xray.pub") layout = Layout.read({ "_type": "layout", "keys": { key_developer["keyid"]: key_developer, key_reviewer["keyid"]: key_reviewer, key_xray["keyid"]: key_xray, key_dependency_owner["keyid"]: key_dependency_owner, }, "steps": [ { "name": "target-develop", "expected_materials": [], "expected_products": [["CREATE", "../target/demo.py"], ["DISALLOW", "*"]], "pubkeys": [key_developer["keyid"]], "expected_command": [], "threshold": 1, }, { "name": "target-code-review", "expected_materials": [[ "MATCH", "../target/demo.py", "WITH", "PRODUCTS", "FROM", "target-develop" ], ["DISALLOW", "*"]], "expected_products": [["ALLOW", "../target/demo.py"], ["DISALLOW", "*"]], "pubkeys": [key_reviewer["keyid"]], "expected_command": [], "threshold": 1, }, { "name": "target-get-dependency", "expected_materials": [], "expected_products": [ ["ALLOW", "../dependency/demo.py"], ["DISALLOW", "*"], ], "pubkeys": [key_dependency_owner["keyid"]], "expected_command": [], "threshold": 1, }, { "name": "target-jfrog-xray", "expected_materials": [ [ "MATCH", "../target/demo.py", "WITH", "PRODUCTS", "FROM", "target-develop" ], ["DISALLOW", "*"], ], "expected_products": [ ["CREATE", "../reports/jfrog-xray-report.json"], ["DISALLOW", "*"], ], "pubkeys": [key_xray["keyid"]], "expected_command": ["python", "generate_report.py"], "threshold": 1, }, ], "inspect": [{ "name": "target-check-vulnerability-report", "expected_materials": [ [ "MATCH", "../reports/jfrog-xray-report.json", "WITH", "PRODUCTS", "FROM", "target-jfrog-xray" ], ], "expected_products": [], "run": ["python", "scripts/validate_jfrog_xray_report.py"], }], }) metadata = Metablock(signed=layout) # Sign and dump layout to "root.layout" metadata.sign(key_owner) metadata.dump("../metadata_target/root.layout")
#!/usr/bin/env python3 import in_toto.models.layout as l import in_toto.models.metadata as m import in_toto.util as util import shlex # keys = util.import_gpg_public_keys_from_keyring_as_dict(['functionary.pub']) project_owner = util.import_rsa_key_from_file('project-owner') layout = l.Layout() keyid = layout.add_functionary_key_from_path('functionary.pub')['keyid'] step = l.Step() step.name = 'build' step.expected_materials = [] step.expected_products = [['CREATE', 'image_id']] step.expected_command = shlex.split( 'docker build . -t empty --idfile image_id') step.pubkeys = [keyid] inspection = l.Inspection() inspection.name = 'verify-image' inspection.expected_materials = [['REQUIRE', 'image_id'], [ 'MATCH', 'image_id', 'WITH', 'PRODUCTS', 'FROM', 'build' ], ['DISALLOW', 'image_id']] inspection.expected_products = [] inspection.run = shlex.split("echo", "lol")