Пример #1
0
    def test_unrecognized_key_type(self):
        """Create and read the wrong key type. """
        wrong_key_type = "wrong_key_type"
        open(wrong_key_type, "w").write(wrong_key_type)

        # Give wrong password whenever prompted.
        with mock.patch('in_toto.util.prompt_password', return_value='x'):
            with self.assertRaises(TypeError):
                import_private_key_from_file(wrong_key_type)
Пример #2
0
def main():
    """Parse arguments, load key from disk (prompts for password if key is
  encrypted) and call in_toto_run.  """
    parser = create_parser()
    args = parser.parse_args()

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

    # Override defaults in settings.py with environment variables and RCfiles
    in_toto.user_settings.set_settings()

    # Regular signing and GPG signing are mutually exclusive
    if (args.key is None) == (args.gpg is None):
        parser.print_usage()
        parser.error("Specify either '--key <key path>' or '--gpg [<keyid>]'")

    # If `--gpg` was set without argument it has the value `True` and
    # we will try to sign with the default key
    gpg_use_default = (args.gpg is True)

    # Otherwise we interpret it as actual keyid
    gpg_keyid = None
    if args.gpg is not True:
        gpg_keyid = args.gpg

    # If no_command is specified run in_toto_run without executing a command
    if args.no_command:
        args.link_cmd = []

    elif not args.link_cmd:  # pragma: no branch
        parser.print_usage()
        parser.error("No command specified."
                     " Please specify (or use the --no-command option)")

    try:
        # We load the key here because it might prompt the user for a password in
        # case the key is encrypted. Something that should not happen in the lib.
        key = None
        if args.key:
            key = util.import_private_key_from_file(args.key, args.key_type)

        runlib.in_toto_run(args.step_name,
                           args.materials,
                           args.products,
                           args.link_cmd,
                           record_streams=args.record_streams,
                           signing_key=key,
                           gpg_keyid=gpg_keyid,
                           gpg_use_default=gpg_use_default,
                           gpg_home=args.gpg_home,
                           exclude_patterns=args.exclude_patterns,
                           base_path=args.base_path,
                           lstrip_paths=args.lstrip_paths,
                           metadata_directory=args.metadata_directory)

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

    sys.exit(0)
Пример #3
0
    def setUpClass(self):
        """Create and change into temporary directory,
    generate key pair, dummy artifact and base arguments. """
        self.set_up_test_dir()
        self.set_up_gpg_keys()

        self.rsa_key_path = "test_key_rsa"
        generate_and_write_rsa_keypair(self.rsa_key_path)
        self.rsa_key = import_private_key_from_file(self.rsa_key_path,
                                                    KEY_TYPE_RSA)

        self.ed25519_key_path = "test_key_ed25519"
        generate_and_write_ed25519_keypair(self.ed25519_key_path)
        self.ed25519_key = import_private_key_from_file(
            self.ed25519_key_path, KEY_TYPE_ED25519)

        self.test_step = "test_step"
        self.test_link_rsa = FILENAME_FORMAT.format(
            step_name=self.test_step, keyid=self.rsa_key["keyid"])
        self.test_link_ed25519 = FILENAME_FORMAT.format(
            step_name=self.test_step, keyid=self.ed25519_key["keyid"])
        self.test_artifact = "test_artifact"
        open(self.test_artifact, "w").close()
Пример #4
0
    def setUpClass(self):
        """Create and change into temporary directory,
    generate key pair, dummy artifact and base arguments. """

        self.working_dir = os.getcwd()

        self.test_dir = tempfile.mkdtemp()

        # Copy gpg keyring
        self.default_gpg_keyid = "8465a1e2e0fb2b40adb2478e18fb3f537e0c8a17"
        self.default_gpg_subkeyid = "c5a0abe6ec19d0d65f85e2c39be9df5131d924e9"
        self.non_default_gpg_keyid = "8288ef560ed3795f9df2c0db56193089b285da58"
        gpg_keyring_path = os.path.join(
            os.path.dirname(os.path.realpath(__file__)), "gpg_keyrings", "rsa")
        self.gnupg_home = os.path.join(self.test_dir, "rsa")
        shutil.copytree(gpg_keyring_path, self.gnupg_home)

        os.chdir(self.test_dir)

        self.rsa_key_path = "test_key_rsa"
        generate_and_write_rsa_keypair(self.rsa_key_path)
        self.rsa_key = import_private_key_from_file(self.rsa_key_path,
                                                    KEY_TYPE_RSA)

        self.ed25519_key_path = "test_key_ed25519"
        generate_and_write_ed25519_keypair(self.ed25519_key_path)
        self.ed25519_key = import_private_key_from_file(
            self.ed25519_key_path, KEY_TYPE_ED25519)

        self.test_step = "test_step"
        self.test_link_rsa = FILENAME_FORMAT.format(
            step_name=self.test_step, keyid=self.rsa_key["keyid"])
        self.test_link_ed25519 = FILENAME_FORMAT.format(
            step_name=self.test_step, keyid=self.ed25519_key["keyid"])
        self.test_artifact = "test_artifact"
        open(self.test_artifact, "w").close()
Пример #5
0
    def test_main_with_encrypted_ed25519_key(self):
        """Test CLI command with encrypted ed25519 key. """
        key_path = "test_key_ed25519_enc"
        password = "******"
        generate_and_write_ed25519_keypair(key_path, password)
        args = [
            "-n", self.test_step, "--key", key_path, "--key-type", "ed25519",
            "--", "ls"
        ]

        with mock.patch('in_toto.util.prompt_password', return_value=password):
            key = import_private_key_from_file(key_path, KEY_TYPE_ED25519)
            linkpath = FILENAME_FORMAT.format(step_name=self.test_step,
                                              keyid=key["keyid"])

            self.assert_cli_sys_exit(args, 0)
            self.assertTrue(os.path.exists(linkpath))
Пример #6
0
 def test_unrecognized_key_type(self):
     """Trigger UnsupportedKeyTypeError. """
     with self.assertRaises(UnsupportedKeyTypeError):
         import_private_key_from_file("ignored_key_path", "wrong_key_type")
Пример #7
0
def _sign_and_dump_metadata(metadata, args):
    """
  <Purpose>
    Internal method to sign link or layout metadata and dump it to disk.

  <Arguments>
    metadata:
            Metablock object (contains Link or Layout object)
    args:
            see argparser

  <Exceptions>
    SystemExit(0) if signing is successful
    SystemExit(2) if any exception occurs

  """

    try:
        if not args.append:
            metadata.signatures = []

        signature = None
        # If the cli tool was called with `--gpg [KEYID ...]` `args.gpg` is
        # a list (not None) and we will try to sign with gpg.
        # If `--gpg-home` was not set, args.gpg_home is None and the signer tries
        # to use the default gpg keyring.
        if args.gpg is not None:
            # If `--gpg` was passed without argument we sign with the default key
            # Excluded so that coverage does not vary in different test environments
            if len(args.gpg) == 0:  # pragma: no cover
                signature = metadata.sign_gpg(gpg_keyid=None,
                                              gpg_home=args.gpg_home)

            # Otherwise we sign with each passed keyid
            for keyid in args.gpg:
                securesystemslib.formats.KEYID_SCHEMA.check_match(keyid)
                signature = metadata.sign_gpg(gpg_keyid=keyid,
                                              gpg_home=args.gpg_home)

        # Alternatively we iterate over passed private key paths `--key KEYPATH
        # ...` load the corresponding key from disk and sign with it
        elif args.key is not None:  # pragma: no branch

            if args.key_type is None:
                args.key_type = [util.KEY_TYPE_RSA] * len(args.key)

            if len(args.key_type) != len(args.key):
                raise securesystemslib.exceptions.FormatError(
                    "number of key_types should match with the number"
                    " of keys specified")

            for idx, key_path in enumerate(args.key):
                key = util.import_private_key_from_file(
                    key_path, args.key_type[idx])
                signature = metadata.sign(key)

        # If `--output` was specified we store the signed link or layout metadata
        # to that location no matter what
        if args.output:
            out_path = args.output

        # Otherwise, in case of links, we build the filename using the link/step
        # name and the keyid of the created signature (there is only one for links)
        elif metadata.type_ == "link":
            securesystemslib.formats.ANY_SIGNATURE_SCHEMA.check_match(
                signature)
            keyid = signature["keyid"]
            out_path = FILENAME_FORMAT.format(step_name=metadata.signed.name,
                                              keyid=keyid)

        # In case of layouts we just override the input file.
        elif metadata.type_ == "layout":  # pragma: no branch
            out_path = args.file

        LOG.info("Dumping {0} to '{1}'...".format(metadata.type_, out_path))

        metadata.dump(out_path)
        sys.exit(0)

    except Exception as e:
        LOG.error("The following error occurred while signing: "
                  "{}".format(e))
        sys.exit(2)
Пример #8
0
def main():
    """Parse arguments, load key from disk (prompts for password if key is
  encrypted) and call in_toto_run. """

    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description="""
Executes the passed command and records paths and hashes of 'materials' (i.e.
files before command execution) and 'products' (i.e. files after command
execution) and stores them together with other information (executed command,
return value, stdout, stderr, ...) to a link metadata file, which is signed
with the passed key.  Returns nonzero value on failure and zero otherwise.""")

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

    parser.epilog = """
examples:
  Tag a git repo, storing files in CWD as products, signing the resulting link
  file with the private key loaded from 'key_file'.

      {prog} -n tag -p . -k key_file -- git tag v1.0


  Create tarball, storing files in 'project' directory as materials and the
  tarball as product, signing the link file with GPG key '...7E0C8A17'.

      {prog} -n package -m project -p project.tar.gz \\
             -g 8465A1E2E0FB2B40ADB2478E18FB3F537E0C8A17 \\
             -- tar czf project.tar.gz project

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

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

    # FIXME: Do we limit the allowed characters for the name?
    named_args.add_argument(
        "-n",
        "--step-name",
        type=str,
        required=True,
        metavar="<name>",
        help=("Name used to associate the resulting link metadata with the"
              " corresponding step defined in an in-toto layout."))

    parser.add_argument(
        "-m",
        "--materials",
        type=str,
        required=False,
        nargs='+',
        metavar="<path>",
        help=
        ("Paths to files or directories, whose paths and hashes are stored in the"
         " resulting link metadata before the command is executed. Symlinks are"
         " followed."))

    parser.add_argument(
        "-p",
        "--products",
        type=str,
        required=False,
        nargs='+',
        metavar="<path>",
        help=
        ("Paths to files or directories, whose paths and hashes are stored in the"
         " resulting link metadata after the command is executed. Symlinks are"
         " followed."))

    named_args.add_argument(
        "-k",
        "--key",
        type=str,
        metavar="<path>",
        help=
        ("Path to a PEM formatted private key file used to sign the resulting"
         " link metadata."
         " (passing one of '--key' or '--gpg' is required)"))

    parser.add_argument(
        "-t",
        "--key-type",
        dest="key_type",
        type=str,
        choices=util.SUPPORTED_KEY_TYPES,
        default=util.KEY_TYPE_RSA,
        help=
        ("Specify the key-type of the key specified by the '--key' option. If"
         " '--key-type' is not passed, default is \"ed25519\"."))

    named_args.add_argument(
        "-g",
        "--gpg",
        nargs="?",
        const=True,
        metavar="<id>",
        help=
        ("GPG keyid used to sign the resulting link metadata.  When '--gpg' is"
         " passed without keyid, the keyring's default GPG key is used."
         " (passing one of '--key' or '--gpg' is required)"))

    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."))

    parser.add_argument(
        "-s",
        "--record-streams",
        dest="record_streams",
        default=False,
        action="store_true",
        help=
        ("If passed 'stdout' and 'stderr' of the executed command are duplicated"
         " and stored in the resulting link metadata."))

    parser.add_argument(
        "-x",
        "--no-command",
        dest="no_command",
        default=False,
        action="store_true",
        help=
        ("Generate link metadata without executing a command, e.g. for a 'signed"
         " off by' step."))

    parser.add_argument(*EXCLUDE_ARGS, **EXCLUDE_KWARGS)
    parser.add_argument(*BASE_PATH_ARGS, **BASE_PATH_KWARGS)
    parser.add_argument(*LSTRIP_PATHS_ARGS, **LSTRIP_PATHS_KWARGS)

    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")

    # FIXME: This is not yet ideal.
    # What should we do with tokens like > or ; ?
    parser.add_argument(
        "link_cmd",
        nargs="*",
        metavar="<command>",
        help=(
            "Command to be executed with options and arguments, separated from"
            " 'in-toto-run' options by double dash '--'."))

    args = parser.parse_args()

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

    # Override defaults in settings.py with environment variables and RCfiles
    in_toto.user_settings.set_settings()

    # Regular signing and GPG signing are mutually exclusive
    if (args.key == None) == (args.gpg == None):
        parser.print_usage()
        parser.error("Specify either `--key <key path>` or `--gpg [<keyid>]`")

    # If `--gpg` was set without argument it has the value `True` and
    # we will try to sign with the default key
    gpg_use_default = (args.gpg == True)

    # Otherwise we interpret it as actual keyid
    gpg_keyid = None
    if args.gpg != True:
        gpg_keyid = args.gpg

    # If no_command is specified run in_toto_run without executing a command
    if args.no_command:
        args.link_cmd = []

    elif not args.link_cmd:  # pragma: no branch
        parser.print_usage()
        parser.error("No command specified."
                     " Please specify (or use the --no-command option)")

    try:
        # We load the key here because it might prompt the user for a password in
        # case the key is encrypted. Something that should not happen in the lib.
        key = None
        if args.key:
            key = util.import_private_key_from_file(args.key, args.key_type)

        runlib.in_toto_run(args.step_name, args.materials, args.products,
                           args.link_cmd, args.record_streams, key, gpg_keyid,
                           gpg_use_default, args.gpg_home,
                           args.exclude_patterns, args.base_path,
                           args.lstrip_paths)

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

    sys.exit(0)