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 replacement API for '*keys' and 'interface' key generation and import #604

Merged
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
97 changes: 97 additions & 0 deletions docs/CRYPTO_SIGNER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

# CryptoSigner

`CryptoSigner` is a modern replacement for the legacy `securesystemslib.keys`
module. It can be used via the `Signer.from_priv_key_uri` API to load private
*rsa*, *ecdsa* and *ed25519* keys from file. It also provides API to generate
in-memory signers for ad-hoc signing.

## Code examples

### Example 1: Ad-hoc signing

`CryptoSigner` provides `generate_{rsa, ed25519, ecdsa}` methods for ad-hoc
signing and signature verification, e.g. in tests or demos.

```python
from securesystemslib.signer import CryptoSigner

signer = CryptoSigner.generate_ed25519()
signature = signer.sign(b"data")
signer.public_key.verify_signature(signature, b"data")
```

### Example 2: Asynchronous key management and signing

The typical Signer API usage is described in
[this blog post](https://theupdateframework.github.io/python-tuf/2023/01/24/securesystemslib-signer-api.html)
and outlined below for a file-based signer.

#### 1. Generate key files
*`CryptoSigner` does not provide API to generate key files. Compatible
keys can be generated with standard tools like `openssl genpkey` (CLI) or
`pyca/cryptography` (Python).*

```python
from cryptography.hazmat.primitives import asymmetric, serialization

# Generate key pair
private_key = asymmetric.ed25519.Ed25519PrivateKey.generate()

# Serialize private key as encrypted PEM/PKCS8
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(b"hunter2"),
)

# Serialize public key as encrypted PEM/subjectPublicKeyInfo
public_pem = private_key.public_key().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)

# Write key files
with open("private.pem", "wb") as f:
f.write(private_pem)
with open("public.pem", "wb") as f:
f.write(public_pem)
```

#### 2. Prepare signing environment

```python
import os
from securesystemslib.signer import SSlibKey

with open("public.pem", "rb") as f:
public_bytes = f.read()

# Make public key, signer URI, and key decryption password available to the
# signer, e.g. via environment variables. The private key file must also be
# available to the signer at the specified path.
os.environ.update({
"SIGNER_URI": "file:private.pem?encrypted=true",
"SIGNER_PUBLIC": public_bytes.decode(),
"SIGNER_SECRET": "hunter2"
})
```

#### 3. Load and use signer

```python
import os
from securesystemslib.signer import SSlibKey, Signer, CryptoSigner, SIGNER_FOR_URI_SCHEME

# NOTE: Registration becomes obsolete once CryptoSigner is the default file signer
SIGNER_FOR_URI_SCHEME.update({CryptoSigner.FILE_URI_SCHEME: CryptoSigner})

# Read signer details
uri = os.environ["SIGNER_URI"]
public_key = SSlibKey.from_pem(os.environ["SIGNER_PUBLIC"].encode())
secrets_handler = lambda sec: os.environ["SIGNER_SECRET"]

# Load and sign
signer = Signer.from_priv_key_uri(uri, public_key, secrets_handler)
signer.sign(b"data")
```
3 changes: 2 additions & 1 deletion securesystemslib/signer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""
from securesystemslib.signer._aws_signer import AWSSigner
from securesystemslib.signer._azure_signer import AzureSigner
from securesystemslib.signer._crypto_signer import CryptoSigner
from securesystemslib.signer._gcp_signer import GCPSigner
from securesystemslib.signer._gpg_signer import GPGKey, GPGSigner
from securesystemslib.signer._hsm_signer import HSMSigner
Expand All @@ -15,14 +16,14 @@
SIGNER_FOR_URI_SCHEME,
SecretsHandler,
Signer,
SSlibSigner,
)
from securesystemslib.signer._sigstore_signer import SigstoreKey, SigstoreSigner
from securesystemslib.signer._spx_signer import (
SpxKey,
SpxSigner,
generate_spx_key_pair,
)
from securesystemslib.signer._sslib_signer import SSlibSigner

# Register supported private key uri schemes and the Signers implementing them
SIGNER_FOR_URI_SCHEME.update(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we change the default handler for FILE_URI_SCHEME? (and maybe leave a comment that ENVVAR_URI_SCHEME is deprecated unless someone reimplements it)

Expand Down
12 changes: 4 additions & 8 deletions securesystemslib/signer/_aws_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,9 @@
import securesystemslib.hash as sslib_hash
from securesystemslib import exceptions
from securesystemslib.exceptions import UnsupportedLibraryError
from securesystemslib.signer._key import Key
from securesystemslib.signer._signer import (
SecretsHandler,
Signature,
Signer,
SSlibKey,
)
from securesystemslib.signer._key import Key, SSlibKey
from securesystemslib.signer._signer import SecretsHandler, Signature, Signer
from securesystemslib.signer._utils import compute_default_keyid

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -127,7 +123,7 @@ def import_(cls, aws_key_id: str, local_scheme: str) -> Tuple[str, Key]:
) from e

keyval = {"public": public_key_pem}
keyid = cls._get_keyid(keytype, local_scheme, keyval)
keyid = compute_default_keyid(keytype, local_scheme, keyval)
public_key = SSlibKey(keyid, keytype, local_scheme, keyval)
return f"{cls.SCHEME}:{aws_key_id}", public_key

Expand Down
12 changes: 4 additions & 8 deletions securesystemslib/signer/_azure_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,9 @@

import securesystemslib.hash as sslib_hash
from securesystemslib.exceptions import UnsupportedLibraryError
from securesystemslib.signer._key import Key
from securesystemslib.signer._signer import (
SecretsHandler,
Signature,
Signer,
SSlibKey,
)
from securesystemslib.signer._key import Key, SSlibKey
from securesystemslib.signer._signer import SecretsHandler, Signature, Signer
from securesystemslib.signer._utils import compute_default_keyid

AZURE_IMPORT_ERROR = None
try:
Expand Down Expand Up @@ -231,7 +227,7 @@ def import_(cls, az_vault_name: str, az_key_name: str) -> Tuple[str, Key]:

keytype, scheme = cls._get_keytype_and_scheme(key_vault_key.key.crv)
keyval = {"public": pem.decode("utf-8")}
keyid = cls._get_keyid(keytype, scheme, keyval)
keyid = compute_default_keyid(keytype, scheme, keyval)
public_key = SSlibKey(keyid, keytype, scheme, keyval)
priv_key_uri = key_vault_key.key.kid.replace("https:", "azurekms:")

Expand Down
Loading