Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple YubiKeys support #583

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
be4edfa
feat: add list yubikeys command
renatav Dec 13, 2024
df3f0b6
feat, WIP: Initial work on iterating over inserted yubikeys
renatav Dec 14, 2024
4bb667c
refact: initial implementation of signing using yubikeys that iterate…
renatav Dec 16, 2024
95ce03b
feat: initial work on storing names of keys in metadata files
renatav Dec 17, 2024
540f0c9
chore: merge feature/tuf-repository and resovle conflicts
renatav Jan 9, 2025
e185ef8
refact: resolve flake issues
renatav Jan 11, 2025
0c08165
feat: add key name to root.json if defined
renatav Jan 11, 2025
f55d0a5
feat: add initial pin manager
renatav Jan 16, 2025
d8cd3a3
refact: move dictionary keeping track of loaded yubikeys to auth repo
renatav Jan 17, 2025
0c5363a
feat, refact: check if yk inserted before signing, move check if load…
renatav Jan 18, 2025
40e6a6e
fix: fix check if only one yubikey inserted
renatav Jan 18, 2025
56a9694
refact: mypy and flake fixes
renatav Jan 18, 2025
fcc9a27
feat: work on loading multiple keys when signing and using key names …
renatav Jan 20, 2025
ef4aedd
refact: update _load_and_append_yubikeys, support loading from multip…
renatav Jan 20, 2025
df29f8a
feat: show names of keys when asking the user to insert yubikeys
renatav Jan 21, 2025
19da186
fix: fix loading single yubikeys and improve messages
renatav Jan 22, 2025
0164576
refact: update yubikey commands to add support for multiple yubikeys
renatav Jan 23, 2025
dfd8b08
refact: allow specification of pin manager not linked with an auth repo
renatav Jan 23, 2025
4c4471a
chore: added pin_manager to api commands and pin_managed decorator to…
renatav Jan 24, 2025
7036b27
feat: add auto continue flag to pin manager
renatav Jan 24, 2025
87eb87a
chore: fix mypy errors
renatav Jan 24, 2025
c43686f
tests: update tests after the addition of pin manager
renatav Jan 24, 2025
dadd79b
fix, refact: fix yubikeys setup when the same yubikeys can be used fo…
renatav Jan 28, 2025
12b0148
fix: fix setting names of keys when there are conflicts, fix loading …
renatav Jan 28, 2025
291d98a
feat: when adding a new role, check if a key name already exists
renatav Jan 29, 2025
16e1608
fix: fix create new role when additional verification keys defined an…
renatav Jan 29, 2025
816809d
chore: formatting and mypy fixes
renatav Jan 29, 2025
09ef0cc
test: update tests after the addition of pin manager
renatav Jan 29, 2025
891905d
fix: iterate over target roles while looking for keys
renatav Jan 29, 2025
29fa0a5
chore: flake and mypy fixes
renatav Jan 29, 2025
f56d466
test: fix sign_target_files
renatav Jan 29, 2025
c98b314
test: fix failing tests
renatav Jan 29, 2025
0e5b5f9
test: fix failing fake yk test
renatav Jan 30, 2025
73848cc
chore: update changelog
renatav Jan 30, 2025
bb97b48
Merge branch 'master' into renatav/multiple-yubikeys
renatav Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ and this project adheres to [Semantic Versioning][semver].

### Added


- Add key names from config files to metadata during repository setup, following updates to TUF and securesystemslib [(583)]
- Implement iteration over all inserted YubiKeys during metadata signing [(583)]
- Implement a `PinManager` class to allow secure pin reuse across API functions and eliminated insecure global pin storage [(583)]
- Implement removal of keys [(561)]
- Implement removal and rotation of keys [(561)]

### Changed
Expand All @@ -19,7 +22,7 @@ Transition to the newest version of TUF [(561)]

### Fixed


[563]: https://github.com/openlawlibrary/taf/pull/563
[561]: https://github.com/openlawlibrary/taf/pull/561


Expand Down
4 changes: 1 addition & 3 deletions taf/api/api_workflow.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from contextlib import contextmanager
from pathlib import Path
from typing import Dict, List, Optional, Union
from typing import List, Optional, Union

from taf.api.utils._conf import find_keystore
from taf.auth_repo import AuthenticationRepository
Expand Down Expand Up @@ -79,13 +79,11 @@ def manage_repo_and_signers(
keystore_path = find_keystore(auth_repo.path)
else:
keystore_path = Path(keystore)
loaded_yubikeys: Dict = {}
for role in roles_to_load:
if not auth_repo.check_if_keys_loaded(role):
keystore_signers, yubikey_signers = load_signers(
auth_repo,
role,
loaded_yubikeys=loaded_yubikeys,
keystore=keystore_path,
scheme=scheme,
prompt_for_keys=prompt_for_keys,
Expand Down
9 changes: 7 additions & 2 deletions taf/api/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from taf.log import taf_logger
from taf.updater.updater import OperationType, clone_repository
import taf.updater.updater as updater
from taf.yubikey.yubikey_manager import PinManager


def _add_to_dependencies(
Expand Down Expand Up @@ -59,6 +60,7 @@ def _add_to_dependencies(
@check_if_clean
def add_dependency(
path: str,
pin_manager: PinManager,
dependency_name: str,
branch_name: str,
out_of_band_commit: str,
Expand Down Expand Up @@ -107,7 +109,7 @@ def add_dependency(
if path is None:
raise TAFError("Authentication repository's path not provided")

auth_repo = AuthenticationRepository(path=path)
auth_repo = AuthenticationRepository(path=path, pin_manager=pin_manager)
if not auth_repo.is_git_repository_root:
taf_logger.error(f"{path} is not a git repository!")
return
Expand Down Expand Up @@ -165,6 +167,7 @@ def add_dependency(
commit_msg = git_commit_message("add-dependency", dependency_name=dependency_name)
register_target_files(
path=path,
pin_manager=pin_manager,
keystore=keystore,
commit=commit,
scheme=scheme,
Expand All @@ -190,6 +193,7 @@ def add_dependency(
@check_if_clean
def remove_dependency(
path: str,
pin_manager: PinManager,
dependency_name: str,
keystore: str,
scheme: Optional[str] = DEFAULT_RSA_SIGNATURE_SCHEME,
Expand Down Expand Up @@ -218,7 +222,7 @@ def remove_dependency(
if path is None:
raise TAFError("Authentication repository's path not provided")

auth_repo = AuthenticationRepository(path=path)
auth_repo = AuthenticationRepository(path=path, pin_manager=pin_manager)
if not auth_repo.is_git_repository_root:
print(f"{path} is not a git repository!")
return
Expand Down Expand Up @@ -249,6 +253,7 @@ def remove_dependency(

register_target_files(
path=path,
pin_manager=pin_manager,
keystore=keystore,
commit=commit,
scheme=scheme,
Expand Down
4 changes: 2 additions & 2 deletions taf/api/keystore.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from taf.models.types import RolesKeysData
from taf.api.utils._conf import find_taf_directory

from taf.api.roles import _initialize_roles_and_keystore
from taf.api.roles import initialize_roles_and_keystore
from taf.keys import get_key_name
from taf.log import taf_logger
from taf.models.types import RolesIterator
Expand Down Expand Up @@ -80,7 +80,7 @@ def generate_keys(
keystore = "./keystore"

taf_logger.log("NOTICE", f"Generating keys in {str(Path(keystore).absolute())}")
roles_key_infos_dict, keystore, _ = _initialize_roles_and_keystore(
roles_key_infos_dict, keystore, _ = initialize_roles_and_keystore(
roles_key_infos, str(keystore)
)

Expand Down
7 changes: 5 additions & 2 deletions taf/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from logging import ERROR
from typing import Dict, List, Optional, Tuple
from logdecorator import log_on_error
from taf.yubikey.yubikey_manager import PinManager
from tuf.api.metadata import Snapshot, Timestamp

from taf.api.utils._git import check_if_clean
Expand Down Expand Up @@ -88,6 +89,7 @@ def print_expiration_dates(
@check_if_clean
def update_metadata_expiration_date(
path: str,
pin_manager: PinManager,
roles: List[str],
interval: Optional[int] = None,
keystore: Optional[str] = None,
Expand Down Expand Up @@ -126,7 +128,7 @@ def update_metadata_expiration_date(
None
"""

auth_repo = AuthenticationRepository(path=path)
auth_repo = AuthenticationRepository(path=path, pin_manager=pin_manager)
if start_date is None:
start_date = datetime.now()

Expand Down Expand Up @@ -178,6 +180,7 @@ def update_metadata_expiration_date(
@check_if_clean
def update_snapshot_and_timestamp(
path: str,
pin_manager: PinManager,
keystore: Optional[str] = None,
roles_to_sync: Optional[List[str]] = None,
scheme: Optional[str] = DEFAULT_RSA_SIGNATURE_SCHEME,
Expand Down Expand Up @@ -208,7 +211,7 @@ def update_snapshot_and_timestamp(
None
"""

auth_repo = AuthenticationRepository(path=path)
auth_repo = AuthenticationRepository(path=path, pin_manager=pin_manager)

with manage_repo_and_signers(
auth_repo,
Expand Down
12 changes: 7 additions & 5 deletions taf/api/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from pathlib import Path
from taf.api.roles import (
_initialize_roles_and_keystore,
initialize_roles_and_keystore,
)
from taf.api.targets import list_targets, register_target_files

Expand All @@ -23,6 +23,7 @@
from taf.tuf.repository import METADATA_DIRECTORY_NAME
from taf.utils import ensure_pre_push_hook
from taf.log import taf_logger
from taf.yubikey.yubikey_manager import PinManager


@log_on_start(
Expand All @@ -38,6 +39,7 @@
)
def create_repository(
path: str,
pin_manager: PinManager,
keystore: Optional[str] = None,
roles_key_infos: Optional[str] = None,
commit: Optional[bool] = False,
Expand Down Expand Up @@ -68,14 +70,15 @@ def create_repository(
keystore_path = find_keystore(path)
if keystore_path is not None:
keystore = str(keystore_path)
roles_key_infos_dict, keystore, skip_prompt = _initialize_roles_and_keystore(
roles_key_infos_dict, keystore, skip_prompt = initialize_roles_and_keystore(
roles_key_infos, keystore
)

roles_keys_data = from_dict(roles_key_infos_dict, RolesKeysData)
auth_repo = AuthenticationRepository(path=path)
auth_repo = AuthenticationRepository(path=path, pin_manager=pin_manager)
signers, verification_keys = load_sorted_keys_of_new_roles(
roles=roles_keys_data.roles,
auth_repo=auth_repo,
yubikeys_data=roles_keys_data.yubikeys,
keystore=keystore,
skip_prompt=skip_prompt,
Expand All @@ -84,8 +87,7 @@ def create_repository(
if signers is None:
return

repository = AuthenticationRepository(path=path)
repository.create(roles_keys_data, signers, verification_keys)
auth_repo.create(roles_keys_data, signers, verification_keys)
if commit:
auth_repo.init_repo()
commit_msg = git_commit_message("create-repo")
Expand Down
Loading