Beispiel #1
0
def import_privatekey_from_file(keypath, password=None):
    # Note: should securesystemslib support this functionality (import any
    # privatekey type)?
    # If the caller does not provide a password argument, prompt for one.
    # Password confirmation is disabled here, which should ideally happen only
    # when creating encrypted key files.
    if password is None:  # pragma: no cover

        # It is safe to specify the full path of 'filepath' in the prompt and not
        # worry about leaking sensitive information about the key's location.
        # However, care should be taken when including the full path in exceptions
        # and log files.
        password = sslib_interface.get_password(
            'Enter a password for'
            ' the encrypted key (' + sslib_interface.TERM_RED + repr(keypath) +
            sslib_interface.TERM_RED + '): ',
            confirm=False)

    # Does 'password' have the correct format?
    sslib_formats.PASSWORD_SCHEMA.check_match(password)

    # Store the encrypted contents of 'filepath' prior to calling the decryption
    # routine.
    encrypted_key = None

    with open(keypath, 'rb') as file_object:
        encrypted_key = file_object.read().decode('utf-8')

    # Decrypt the loaded key file, calling the 'cryptography' library to generate
    # the derived encryption key from 'password'.  Raise
    # 'securesystemslib.exceptions.CryptoError' if the decryption fails.
    try:
        key_object = sslib_keys.decrypt_key(encrypted_key, password)

    except sslib_exceptions.CryptoError:
        try:
            logger.debug(
                'Decryption failed.  Attempting to import a private PEM instead.'
            )
            key_object = sslib_keys.import_rsakey_from_private_pem(
                encrypted_key, 'rsassa-pss-sha256', password)

        except sslib_exceptions.CryptoError as error:
            raise exceptions.Error(
                repr(keypath) + ' cannot be '
                ' imported, possibly because an invalid key file is given or '
                ' the decryption password is incorrect.') from error

    if key_object['keytype'] not in SUPPORTED_KEY_TYPES:
        raise exceptions.Error('Trying to import an unsupported key'
                               ' type: ' + repr(key_object['keytype'] + '.'
                                                '  Supported key types: ' +
                                                repr(SUPPORTED_KEY_TYPES)))

    else:
        # Add "keyid_hash_algorithms" so that equal keys with different keyids can
        # be associated using supported keyid_hash_algorithms.
        key_object['keyid_hash_algorithms'] = sslib_settings.HASH_ALGORITHMS

        return key_object
Beispiel #2
0
def write_and_read_new_keys(trust_dir: str, functionary: str, threshold: Threshold) -> Keyring:
    # NOTE: By default, we expect to store keys in ~/.signy/private (like ~/.docker/private).
    keystore_dir = os.path.expanduser(os.path.join(trust_dir, 'private'))
    keypairs = []
    for i in range(1, threshold.n + 1):
        print(f'Writing key {i}/{threshold.n} for the "{functionary}" functionary...')
        passphrase = get_password(
            prompt='Please enter a NON-EMPTY passphrase to ENCRYPT this key: ',
            confirm=True)
        keypath = write_keypair(keystore_dir, functionary, i, threshold.n, passphrase)
        keypair = read_keypair(functionary, keypath, i, threshold.n, passphrase)
        # Rename the private and public keys to match the keyid instead.
        # Why? So that we know how to find keys later on repository / disk.
        rename_keys_to_match_keyid(keystore_dir, keypair, functionary, i, threshold.n)
        keypairs.append(keypair)
        print()
    return Keyring(threshold, tuple(keypairs))
Beispiel #3
0
def create_and_set_keys(keystore_dir, repo_obj):
    for rolename in ('root', 'timestamp', 'snapshot', 'targets'):
        passphrase = os.environ.get('{}_PASSPHRASE'.format(rolename.upper()))
        if not passphrase:
            passphrase = get_password(
                prompt='Enter password for {}: '.format(rolename),
                confirm=True)

        private_keypath = str(get_private_keypath(keystore_dir, rolename))
        public_keypath = get_public_keypath(private_keypath)

        generate_and_write_ecdsa_keypair(private_keypath, password=passphrase)

        private = import_ecdsa_privatekey_from_file(private_keypath,
                                                    passphrase)
        public = import_ecdsa_publickey_from_file(public_keypath)

        role_obj = getattr(repo_obj, rolename)
        role_obj.load_signing_key(private)
        role_obj.add_verification_key(public)
Beispiel #4
0
def remove_targets(parsed_arguments):
    repository = repo_tool.load_repository(
        os.path.join(parsed_arguments.path, REPO_DIR))

    # Remove target files from the Targets metadata (or the role specified in
    # --role) that match the glob patterns specified in --remove.
    remove_target_files_from_metadata(parsed_arguments, repository)

    # Examples of how the --pw command-line option is interpreted:
    # repo.py --init': parsed_arguments.pw = 'pw'
    # repo.py --init --pw my_password: parsed_arguments.pw = 'my_password'
    # repo.py --init --pw: The user is prompted for a password, as follows:
    if not parsed_arguments.pw:
        parsed_arguments.pw = sslib_interface.get_password(
            prompt='Enter a password for the top-level role keys: ',
            confirm=True)

    targets_private = import_privatekey_from_file(
        os.path.join(parsed_arguments.path, KEYSTORE_DIR, TARGETS_KEY_NAME),
        parsed_arguments.targets_pw)
    repository.targets.load_signing_key(targets_private)

    # Load the top-level keys for Snapshot and Timestamp to make a new release.
    # Automatically making a new release can be disabled via --no_release.
    if not parsed_arguments.no_release:
        snapshot_private = import_privatekey_from_file(
            os.path.join(parsed_arguments.path, KEYSTORE_DIR,
                         SNAPSHOT_KEY_NAME), parsed_arguments.snapshot_pw)
        timestamp_private = import_privatekey_from_file(
            os.path.join(parsed_arguments.path, KEYSTORE_DIR,
                         TIMESTAMP_KEY_NAME), parsed_arguments.timestamp_pw)

        repository.snapshot.load_signing_key(snapshot_private)
        repository.timestamp.load_signing_key(timestamp_private)

    consistent_snapshot = roledb.get_roleinfo(
        'root', repository._repository_name)['consistent_snapshot']
    repository.writeall(consistent_snapshot=consistent_snapshot)

    # Move staged metadata directory to "live" metadata directory.
    write_to_live_repo(parsed_arguments)