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

Add priv key uri support to SignerStore #451

Merged
merged 1 commit into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 29 additions & 8 deletions repository_service_tuf_worker/signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,21 @@
# SPDX-License-Identifier: MIT

from dynaconf import Dynaconf
from securesystemslib.signer import Key, Signer
from securesystemslib.signer import (
SIGNER_FOR_URI_SCHEME,
CryptoSigner,
Key,
Signer,
)

from repository_service_tuf_worker.interfaces import IKeyVault

RSTUF_ONLINE_KEY_URI_FIELD = "x-rstuf-online-key-uri"

# Register non-default securesystemslib file signer
# secure-systems-lab/securesystemslib#617
SIGNER_FOR_URI_SCHEME[CryptoSigner.FILE_URI_SCHEME] = CryptoSigner


class SignerStore:
"""Generic signer store."""
Expand All @@ -16,15 +27,25 @@ def __init__(self, settings: Dynaconf):
self._signers: dict[str, Signer] = {}

def get(self, key: Key) -> Signer:
"""Return signer for passed key."""
"""Return signer for passed key.

- signer is loaded from the uri included in the passed public key
(see SIGNER_FOR_URI_SCHEME for available uri schemes)
- RSTUF_KEYVAULT_BACKEND is used as fallback, if no URI is included

"""

if key.keyid not in self._signers:
vault = self._settings.get("KEYVAULT")
if not isinstance(vault, IKeyVault):
raise ValueError(
"RSTUF_KEYVAULT_BACKEND is required for online signing"
)
if uri := key.unrecognized_fields.get(RSTUF_ONLINE_KEY_URI_FIELD):
self._signers[key.keyid] = Signer.from_priv_key_uri(uri, key)

else:
vault = self._settings.get("KEYVAULT")
if not isinstance(vault, IKeyVault):
raise ValueError(
"RSTUF_KEYVAULT_BACKEND is required for online signing"
)

self._signers[key.keyid] = vault.get(key)
self._signers[key.keyid] = vault.get(key)

return self._signers[key.keyid]
3 changes: 3 additions & 0 deletions tests/files/pem/ed25519_private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIGiI3w9x2HZ9UKGi51USN5JN2wtppaYVCRIBTp8ESaj3
-----END PRIVATE KEY-----
39 changes: 36 additions & 3 deletions tests/unit/tuf_repository_service_worker/test_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@
#
# SPDX-License-Identifier: MIT

from pathlib import Path

import pytest
from pretend import stub
from securesystemslib.signer import CryptoSigner, Key

from repository_service_tuf_worker.interfaces import IKeyVault
from repository_service_tuf_worker.signer import SignerStore
from repository_service_tuf_worker.signer import (
RSTUF_ONLINE_KEY_URI_FIELD,
SignerStore,
)

_FILES = Path(__file__).parent.parent.parent / "files"


class TestSigner:
Expand Down Expand Up @@ -36,7 +44,7 @@ def get(self, public_key):

fake_id = "fake_id"
fake_signer = stub()
fake_key = stub(keyid=fake_id)
fake_key = stub(keyid=fake_id, unrecognized_fields={})
fake_settings = stub(get=lambda x: FakeKeyVault())

store = SignerStore(fake_settings)
Expand All @@ -47,10 +55,35 @@ def get(self, public_key):

def test_get_no_vault(self):
fake_id = "fake_id"
fake_key = stub(keyid=fake_id)
fake_key = stub(keyid=fake_id, unrecognized_fields={})
fake_settings = stub(get=lambda x: None)

store = SignerStore(fake_settings)

with pytest.raises(ValueError):
store.get(fake_key)

def test_get_from_file_uri(self):
path = _FILES / "pem" / "ed25519_private.pem"
uri = f"file:{path}?encrypted=false"

key_metadata = {
"keytype": "ed25519",
"scheme": "ed25519",
"keyval": {
"public": (
"4f66dabebcf30628963786001984c0b7"
"5c175cdcf3bc4855933a2628f0cd0a0f"
)
},
RSTUF_ONLINE_KEY_URI_FIELD: uri,
}

fake_id = "fake_id"
key = Key.from_dict(fake_id, key_metadata)

fake_settings = stub()
store = SignerStore(fake_settings)
signer = store.get(key)

assert isinstance(signer, CryptoSigner)
Loading