Beispiel #1
0
 def test_verify_failing_bad_signature(self):
     """Test fail verification with bad layout signature. """
     layout = Metablock.load(self.layout_bad_sig)
     layout_key_dict = import_rsa_public_keys_from_files_as_dict(
         [self.alice_path])
     with self.assertRaises(SignatureVerificationError):
         in_toto_verify(layout, layout_key_dict)
Beispiel #2
0
 def test_verify_failing_missing_key(self):
     """Test fail verification with missing layout key. """
     layout = Metablock.load(self.layout_double_signed_path)
     layout_key_dict = import_rsa_public_keys_from_files_as_dict(
         [self.bob_path])
     with self.assertRaises(SignatureVerificationError):
         in_toto_verify(layout, layout_key_dict)
Beispiel #3
0
 def test_verify_failing_inspection_exits_non_zero(self):
     """Test fail verification with inspection returning non-zero. """
     layout = Metablock.load(self.layout_failing_inspection_retval)
     layout_key_dict = import_rsa_public_keys_from_files_as_dict(
         [self.alice_path])
     with self.assertRaises(BadReturnValueError):
         in_toto_verify(layout, layout_key_dict)
Beispiel #4
0
    def __verify_in_toto_metadata(self, target_relpath, in_toto_inspection_packet):
        # Make a temporary directory in a parent directory we control.
        tempdir = tempfile.mkdtemp(dir=REPOSITORIES_DIR)

        # Copy files over into temp dir.
        for rel_path in in_toto_inspection_packet:
            # Don't confuse Python with any leading path separator.
            rel_path = rel_path.lstrip('/')
            abs_path = os.path.join(self.__targets_dir, rel_path)
            shutil.copy(abs_path, tempdir)

        # Switch to the temp dir.
        os.chdir(tempdir)

        # Load the root layout and public keys.
        layout = Metablock.load('root.layout')
        pubkeys = glob.glob('*.pub')
        layout_key_dict = import_public_keys_from_files_as_dict(pubkeys)
        # Parameter substitution.
        params = substitute(target_relpath)

        try:
            verifylib.in_toto_verify(layout, layout_key_dict, substitution_parameters=params)
        except:
            logger.exception('in-toto failed to verify {}'.format(target_relpath))
            raise
        else:
            logger.info('in-toto verified {}'.format(target_relpath))
        finally:
            # Switch back to a parent directory we control, so that we can
            # safely delete temp dir.
            os.chdir(REPOSITORIES_DIR)
            # Delete temp dir.
            shutil.rmtree(tempdir)
Beispiel #5
0
    def __in_toto_verify(self, inspection_packet, target_relpath):
        # Make a temporary directory in a parent directory we control.
        tempdir = tempfile.mkdtemp(dir=REPOSITORIES_DIR)

        # Copy files over into temp dir.
        for abs_path in inspection_packet:
            shutil.copy(abs_path, tempdir)

        # Switch to the temp dir.
        os.chdir(tempdir)

        # Load the root layout and public keys in this temp dir.
        root_layout, root_layout_pubkeys, root_layout_params = self.__load_root_layout(
            target_relpath)

        try:
            verifylib.in_toto_verify(
                root_layout,
                root_layout_pubkeys,
                substitution_parameters=root_layout_params)
        except Exception as e:
            self.__handle_in_toto_verification_exception(target_relpath, e)
        else:
            logger.info('in-toto verified {}'.format(target_relpath))
        finally:
            # Switch back to a parent directory we control, so that we can
            # safely delete temp dir.
            os.chdir(REPOSITORIES_DIR)
            # Delete temp dir.
            shutil.rmtree(tempdir)
Beispiel #6
0
 def test_verify_failing_inspection_rules(self):
     """Test fail verification with failing inspection artifact rule. """
     layout = Metablock.load(self.layout_failing_inspection_rule_path)
     layout_key_dict = import_rsa_public_keys_from_files_as_dict(
         [self.alice_path])
     with self.assertRaises(RuleVerficationError):
         in_toto_verify(layout, layout_key_dict)
def main():
    args = parse_arguments()

    # configure our instance of the grafeas api
    swagger_client.configuration.host = args.target
    api_instance = swagger_client.GrafeasApi()

    try:
        pubkey = util.import_rsa_public_keys_from_files_as_dict([args.key])
        layout = fetch_layout(args.project_id, api_instance)

    except Exception as e:
        print("Exception when fetching the in-toto layout\n{}: {}".format(
            type(e).__name__, e))
        sys.exit(1)

    # fetch the link metadata for every step
    for step in layout.signed.steps:
        for keyid in step.pubkeys:
            try:
                fetch_occurrence(args.project_id, step.name, keyid,
                                 api_instance)
            except ApiException as e:
                raise e
                pass

    try:
        verifylib.in_toto_verify(layout, pubkey)
    except Exception as e:
        print("Exception when verifying the supply chain\n{}: {}".format(
            type(e).__name__, e))
        sys.exit(1)
Beispiel #8
0
 def test_verify_failing_layout_expired(self):
     """Test fail verification with expired layout. """
     layout = Metablock.load(self.layout_expired_path)
     layout_key_dict = import_rsa_public_keys_from_files_as_dict(
         [self.alice_path, self.bob_path])
     with self.assertRaises(LayoutExpiredError):
         in_toto_verify(layout, layout_key_dict)
Beispiel #9
0
 def test_verify_failing_link_metadata_files(self):
     """Test fail verification with link metadata files not found. """
     os.rename("package.2f89b927.link", "package.link.bak")
     layout = Metablock.load(self.layout_single_signed_path)
     layout_key_dict = import_rsa_public_keys_from_files_as_dict(
         [self.alice_path])
     with self.assertRaises(in_toto.exceptions.LinkNotFoundError):
         in_toto_verify(layout, layout_key_dict)
     os.rename("package.link.bak", "package.2f89b927.link")
  def test_substitute(self):
    """Do a simple substitution on the expected_command field"""
    signed_layout = Metablock(signed=self.layout)
    signed_layout.sign(self.alice)

    # we will catch a LinkNotFound error because we don't have (and don't need)
    # the metadata.
    with self.assertRaises(in_toto.exceptions.LinkNotFoundError):
      in_toto_verify(signed_layout, self.alice_pub_dict,
          substitution_parameters={"EDITOR":"vim"})

    self.assertEqual(self.layout.steps[0].expected_command[0], "vim")
Beispiel #11
0
    def test_grafeas_occurrence_to_in_toto_link_verify(self):
        """Test in-toto-verify on in-toto link generated from Grafeas occurrence.
    """
        for f in os.listdir("occurrences"):
            occurrence = GrafeasInTotoOccurrence.load(
                os.path.join("occurrences", f))
            # this is hacky, yes, but since we control the test metadata...
            step_name, keyid, _ = f.split(".")
            in_toto_link = occurrence.to_link(step_name)
            in_toto_link.dump("in-toto-verify-links/{}.{}.link".format(
                step_name, keyid))

        # The test passes if in_toto_verify passes
        in_toto_verify(self.metadata,
                       self.layout_key_dict,
                       link_dir_path="in-toto-verify-links")
Beispiel #12
0
def in_toto_verify(layout_path, layout_key_paths):
    """
  <Purpose>
    Loads the layout metadata as Metablock object (containg a Layout object)
    and the signature verification keys from the passed paths,
    calls   verifylib.in_toto_verify   and handles exceptions.

  <Arguments>
    layout_path:
            Path to layout metadata file that is being verified.

    layout_key_paths:
            List of paths to project owner public keys, used to verify the
            layout's signature.

  <Exceptions>
    SystemExit if any exception occurs

  <Side Effects>
    Calls sys.exit(1) if an exception is raised

  <Returns>
    None.

  """
    try:
        log.info("Verifying software supply chain...")

        log.info("Reading layout...")
        layout = Metablock.load(layout_path)

        log.info("Reading layout key(s)...")
        layout_key_dict = in_toto.util.import_rsa_public_keys_from_files_as_dict(
            layout_key_paths)

        verifylib.in_toto_verify(layout, layout_key_dict)
    except Exception as e:
        log.fail_verification("{0} - {1}".format(type(e).__name__, e))
        sys.exit(1)
Beispiel #13
0
def main():
    """Parse arguments and call in_toto_verify. """
    parser = create_parser()
    args = parser.parse_args()

    LOG.setLevelVerboseOrQuiet(args.verbose, args.quiet)

    # For verifying at least one of --layout-keys or --gpg must be specified
    # Note: Passing both at the same time is possible.
    if (args.layout_keys is None) and (args.gpg is None):
        parser.print_help()
        parser.error("wrong arguments: specify at least one of"
                     " '--layout-keys path [path ...]' or '--gpg id [id ...]'")

    try:
        LOG.info("Loading layout...")
        layout = Metablock.load(args.layout)

        layout_key_dict = {}
        if args.layout_keys is not None:
            LOG.info("Loading layout key(s)...")
            layout_key_dict.update(
                in_toto.util.import_public_keys_from_files_as_dict(
                    args.layout_keys, args.key_types))

        if args.gpg is not None:
            LOG.info("Loading layout gpg key(s)...")
            layout_key_dict.update(
                in_toto.util.import_gpg_public_keys_from_keyring_as_dict(
                    args.gpg, gpg_home=args.gpg_home))

        verifylib.in_toto_verify(layout, layout_key_dict, args.link_dir)

    except Exception as e:
        LOG.error("(in-toto-verify) {0}: {1}".format(type(e).__name__, e))
        sys.exit(1)

    sys.exit(0)
Beispiel #14
0
    def __verify_in_toto_metadata(self, target_relpath,
                                  in_toto_metadata_relpaths, pubkey_relpaths):
        # Make a temporary directory.
        tempdir = tempfile.mkdtemp()
        prev_cwd = os.getcwd()

        try:
            # Copy files over into temp dir.
            rel_paths = [target_relpath
                         ] + in_toto_metadata_relpaths + pubkey_relpaths
            for rel_path in rel_paths:
                # Don't confuse Python with any leading path separator.
                rel_path = rel_path.lstrip('/')
                abs_path = os.path.join(self.__targets_dir, rel_path)
                shutil.copy(abs_path, tempdir)

            # Switch to the temp dir.
            os.chdir(tempdir)

            # Load the root layout and public keys.
            layout = Metablock.load('root.layout')
            pubkeys = glob.glob('*.pub')
            layout_key_dict = import_public_keys_from_files_as_dict(pubkeys)
            # Verify and inspect.
            params = substitute(target_relpath)
            verifylib.in_toto_verify(layout,
                                     layout_key_dict,
                                     substitution_parameters=params)
            logger.info('in-toto verified {}'.format(target_relpath))
        except:
            logger.exception(
                'in-toto failed to verify {}'.format(target_relpath))
            raise
        finally:
            os.chdir(prev_cwd)
            # Delete temp dir.
            shutil.rmtree(tempdir)
Beispiel #15
0
 def test_verify_passing_double_signed_layout(self):
     """Test pass verification of double-signed layout. """
     layout = Metablock.load(self.layout_double_signed_path)
     layout_key_dict = import_rsa_public_keys_from_files_as_dict(
         [self.alice_path, self.bob_path])
     in_toto_verify(layout, layout_key_dict)
Beispiel #16
0
def main():
    """Parse arguments and call in_toto_verify. """

    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description="""
Verifies that a software supply chain was carried out according to the passed
in-toto supply chain layout.

The verification includes the following checks:
  * the layout was signed with the the passed key(s),
  * the layout has not expired,
  * signed link metadata files exist for each step of the layout in the CWD,
  * link files are provided by the required number of authorized functionaries,
  * the materials and products for each step, as reported by the corresponding
    link files, adhere to the artifact rules specified by the step.

Additionally, inspection commands defined in the layout are executed
sequentially, followed by applying the inspection's artifact rules.

The command returns a nonzero value if verification fails and zero otherwise.
""")

    parser.usage = "%(prog)s <named arguments> [optional arguments]"

    parser.epilog = """
examples:
  Verify supply chain in 'root.layout', signed with private part of
  'key_file.pub'.

      {prog} --layout root.layout --layout-keys key_file.pub


  Verify supply chain like above but load links corresponding to steps of
  root.layout from 'link_dir'.

      {prog} --layout root.layout --layout-keys key_file.pub \\
          --link-dir link_dir


  Verify supply chain in 'root.layout', signed with GPG key '...7E0C8A17',
  whose public part can be found in the GPG keyring at '~/.gnupg'.

      {prog} --layout root.layout \\
      --gpg 8465A1E2E0FB2B40ADB2478E18FB3F537E0C8A17 --gpg-home ~/.gnupg


""".format(prog=parser.prog)

    named_args = parser.add_argument_group("required named arguments")

    named_args.add_argument(
        "-l",
        "--layout",
        type=str,
        required=True,
        metavar="<path>",
        help=("Path to root layout specifying the software supply chain to be"
              " verified."))

    named_args.add_argument(
        "-k",
        "--layout-keys",
        type=str,
        metavar="<path>",
        nargs="+",
        help=
        ("Path(s) to PEM formatted public key(s), used to verify the passed root"
         " layout's signature(s)."
         " Passing at least one key using '--layout-keys' and/or '--gpg' is"
         " required. For each passed key the layout must carry a valid"
         " signature."))

    named_args.add_argument(
        "-g",
        "--gpg",
        nargs="+",
        metavar="<id>",
        help=
        ("GPG keyid, identifying a public key in the GPG keychain, used to verify"
         " the passed root layout's signature(s)."
         " Passing at least one key using '--layout-keys' and/or '--gpg' is"
         " required. For each passed key the layout must carry a valid"
         " signature."))

    parser.add_argument(
        "--link-dir",
        dest="link_dir",
        type=str,
        metavar="<path>",
        default=".",
        help=(
            "Path to directory where link metadata files for steps defined in"
            " the root layout should be loaded from. If not passed links are"
            " loaded from the current working directory."))

    parser.add_argument(
        "--gpg-home",
        dest="gpg_home",
        type=str,
        metavar="<path>",
        help=
        ("Path to GPG keyring to load GPG key identified"
         " by '--gpg' option.  If '--gpg-home' is not passed, the default GPG"
         " keyring is used."))

    verbosity_args = parser.add_mutually_exclusive_group(required=False)
    verbosity_args.add_argument("-v",
                                "--verbose",
                                dest="verbose",
                                help="Verbose execution.",
                                action="store_true")

    verbosity_args.add_argument("-q",
                                "--quiet",
                                dest="quiet",
                                help="Suppress all output.",
                                action="store_true")

    args = parser.parse_args()

    log.setLevelVerboseOrQuiet(args.verbose, args.quiet)

    # For verifying at least one of --layout-keys or --gpg must be specified
    # Note: Passing both at the same time is possible.
    if (args.layout_keys == None) and (args.gpg == None):
        parser.print_help()
        parser.error("wrong arguments: specify at least one of"
                     " `--layout-keys path [path ...]` or `--gpg id [id ...]`")

    try:
        log.info("Loading layout...")
        layout = Metablock.load(args.layout)

        layout_key_dict = {}
        if args.layout_keys != None:
            log.info("Loading layout key(s)...")
            layout_key_dict.update(
                in_toto.util.import_rsa_public_keys_from_files_as_dict(
                    args.layout_keys))

        if args.gpg != None:
            log.info("Loading layout gpg key(s)...")
            layout_key_dict.update(
                in_toto.util.import_gpg_public_keys_from_keyring_as_dict(
                    args.gpg, gpg_home=args.gpg_home))

        verifylib.in_toto_verify(layout, layout_key_dict, args.link_dir)

    except Exception as e:
        log.error("(in-toto-verify) {0}: {1}".format(type(e).__name__, e))
        sys.exit(1)

    sys.exit(0)
# we have a TUF-vetted package now, but we can dive a little bit further back
# now :)
client.download_target(package_info, 'client')
x_in_toto = package_info['fileinfo']['custom']['x-in-toto']
for _target in x_in_toto:
    in_toto_md_info = client.get_one_valid_targetinfo(_target)
    client.download_target(in_toto_md_info, 'client')

# we should be ready for in-toto verification

print("Setting up test hardness for in-toto verification")
alice = import_ed25519_publickey_from_file('./keys/alice.pub')
layout_keys = {x['keyid']: x for x in [alice]}
shutil.copyfile("client/packages/demo-project.tar.gz",
                "in_toto_md/demo-project.tar.gz")

for _file in glob.glob("client/layouts/*"):
    shutil.copyfile(_file, os.path.join("in_toto_md", os.path.basename(_file)))

os.chdir("in_toto_md")
layout = Metablock.load('root.layout')

# if things are horrible, this will throw a nasty exception. You just wait...
print("Running in-toto verification")
verifylib.in_toto_verify(layout, layout_keys)

# Since it didn't, we can probably copy our target to the main directory
print("Successfully verified with TUF and in-toto!")
shutil.copyfile('demo-project.tar.gz', '../demo-project.tar.gz')