Secure Systems Library
Securesystemslib is a Python library that provides cryptographic and general-purpose routines for Secure Systems Lab projects at NYU. It serves as a cryptography interface for signing and verifying digital signatures, particularly developed for the TUF and in-toto projects. The library is actively maintained, with a recent major focus on a new 'signer' API. Its release cadence is driven by new feature additions, security enhancements, and deprecations related to key management and signing systems.
Common errors
-
ModuleNotFoundError: No module named 'securesystemslib.keys'
cause Attempting to import a deprecated module (`keys`, `ecdsa_keys`, `rsa_keys`, or `ed25519_keys`). These modules were marked for deprecation in v0.29.0.fixRefactor your code to use the `securesystemslib.signer` API, specifically `CryptoSigner` or other specific signers for your use case. -
securesystemslib.exceptions.UnsupportedAlgorithmError: md5 is not a supported hash algorithm
cause Attempting to use `md5` or `sha1` as a hash algorithm, which were removed in version 0.28.0. [GitHub release notes]fixUpdate your code to use stronger, supported hash algorithms like `sha256` or `sha512`. -
TypeError: SigstoreSigner.import_via_auth() takes 0 positional arguments but 1 was given
cause Using the old `SigstoreSigner` API with a `sigstore-python` version that expects a different interface, likely due to the breaking change in `securesystemslib v0.30.0` adapting to `sigstore-python 2.0`.fixReview the `sigstore-python` documentation and the `securesystemslib` `0.30.0` changelog. The `import_via_auth` method now expects no arguments, or the signature has changed. Adapt your call accordingly. -
RuntimeError: Python 3.7 is no longer supported
cause Running `securesystemslib` version `0.30.0` or higher on a Python 3.7 environment. Python 3.7 reached EOL and support was dropped.fixUpgrade your Python installation to version 3.8 or newer to meet the library's minimum requirements.
Warnings
- breaking Python 3.7 reached End-of-Life on June 27, 2023, and `securesystemslib` officially dropped support for it in version `0.30.0`. Running on Python 3.7 or older will lead to compatibility issues and lack of security updates.
- deprecated The `securesystemslib.keys`, `securesystemslib.ecdsa_keys`, `securesystemslib.rsa_keys`, and `securesystemslib.ed25519_keys` modules, along with `SSLibSigner`, are deprecated in favor of the new `securesystemslib.signer` API, specifically `CryptoSigner`.
- breaking Support for weak cryptographic hash algorithms `md5` and `sha1` was removed in `securesystemslib` version `0.28.0` due to security concerns. [GitHub release notes]
- breaking The `SigstoreSigner` API was adapted to `sigstore-python 2.0` in version `0.30.0`, changing how signing identities are managed, particularly for interactive credential handling.
- gotcha By default, functions like `securesystemslib.interface.generate_and_write_unencrypted_ed25519_keypair()` (from the legacy API) might create private key files with world-readable permissions, depending on the system's umask. This can expose private keys to other users on a shared system.
Install
-
pip install securesystemslib -
pip install securesystemslib[crypto] -
pip install securesystemslib[sigstore]
Imports
- CryptoSigner
from securesystemslib.signer import CryptoSigner
- SSLibSigner
from securesystemslib.interface import generate_and_write_rsa_keypair
from securesystemslib.signer import SSLibSigner
- Key
from securesystemslib.signer import Key
Quickstart
import os
import json
from securesystemslib.signer import CryptoSigner, Key
from securesystemslib.formats import encode_canonical_json
# 1. Generate a new key pair using the CryptoSigner (e.g., RSA)
# In a real scenario, you'd protect the private key with a strong password
# or use a KMS. For quickstart, we'll use a placeholder password.
# Create a temporary directory for keys
if not os.path.exists("temp_keys"): os.makedirs("temp_keys")
passphrase = os.environ.get('SECURESYSTEMSLIB_PASSPHRASE', 'secret-password')
# Generate an RSA key pair
private_key_path = os.path.join("temp_keys", "example_key")
signer = CryptoSigner.generate_and_write_key(private_key_path, keytype="rsa", algorithm="rsassa-pss-sha256", passphrase=passphrase)
# The public key details are part of the signer object
public_key = signer.public_key
print(f"Generated public key ID: {public_key.keyid}")
# 2. Prepare some data to sign
data_to_sign = {"message": "Hello, securesystemslib!", "timestamp": 1678886400}
canonical_data = encode_canonical_json(data_to_sign).encode("utf-8")
# 3. Sign the data
signature = signer.sign(canonical_data)
print(f"Generated signature: {signature.signature[:20]}...")
# 4. Verify the signature
# A Key object can be created from the public_key dictionary
verifier_key = Key.from_dict(public_key.keyid, public_key.to_dict())
# Verify using the signer and the original data
try:
CryptoSigner.verify_signature(signature, verifier_key, canonical_data)
print("Signature verification successful!")
except Exception as e:
print(f"Signature verification failed: {e}")
# Clean up temporary files (optional)
os.remove(private_key_path)
os.remove(private_key_path + ".pub")
os.rmdir("temp_keys")