From db459d07ea2a0b8fe78bd45ea3349b8c0ccb3f51 Mon Sep 17 00:00:00 2001 From: Lukas Puehringer Date: Mon, 21 Aug 2023 17:21:11 +0200 Subject: [PATCH 1/2] docs: rewrite README - Switch from rst to markdown (syntax is just so much easier) - Add honest project description (securesystemslib is for TUF and in-toto). - Remove wordy Overview section. Relevant information about crypto backends, and key types and formats should be documented as part of the API on RTD. - Replace legacy interface snippets in Usage section with link to securesystemslib RTD page. Legacy interfaces have functional replacements in the new Signer API, i.e. CryptoSigner for file-based RSA, ed25519, ecdsa keys, and GPGSigner for GPG keys. Signer API docs are still WIP (see #622), but already seem more useful than the legacy docs. And we definitely don't want to encourage anyone to use legacy interfaces. - Shorten installation/testing sections. Signed-off-by: Lukas Puehringer --- README.md | 40 +++++ README.rst | 388 ------------------------------------------------- pyproject.toml | 2 +- 3 files changed, 41 insertions(+), 389 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 00000000..f841019f --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# securesystemslib + +[![CI](https://github.com/secure-systems-lab/securesystemslib/workflows/Run%20Securesystemslib%20tests/badge.svg)](https://github.com/secure-systems-lab/securesystemslib/actions?query=workflow%3A%22Run+Securesystemslib+tests%22+branch%3Amain) + +A cryptography interface to sign and verify +[TUF](https://theupdateframework.io) and [in-toto](https://in-toto.io) +metadata. + +## Installation + +The default installation supports [pure-Python `ed25519` signature +verification](https://github.com/pyca/ed25519) only. To enable other schemes and +signature creation, `securesystemslib` can be installed with *extras*. See +[pyproject.toml](pyproject.toml) for available *optional dependencies*. + +```bash +# Install with ed25519, RSA, ECDSA sign and verify support +pip install securesystemslib[crypto] +``` + +## Usage +[python-securesystemslib.readthedocs.io](https://python-securesystemslib.readthedocs.io) + +## Contact +- Questions and discussions: + [`#securesystemslib-python`](https://cloud-native.slack.com/archives/C05PF3GA7AL) + on [CNCF Slack](https://communityinviter.com/apps/cloud-native/cncf) +- Security issues: [*Draft a new security + advisory*](https://github.com/secure-systems-lab/securesystemslib/security/advisories/new) +- Other issues and requests: [*Open a new + issue*](https://github.com/secure-systems-lab/securesystemslib/issues/new) + +## Testing +`tox` is used for testing. It can be installed via +[pip](https://tox.wiki/en/4.9.0/installation.html#via-pip) and executed from the +command line in the root of the repository. + +```bash +tox +``` diff --git a/README.rst b/README.rst deleted file mode 100644 index acaca71b..00000000 --- a/README.rst +++ /dev/null @@ -1,388 +0,0 @@ -Secure Systems Library ----------------------- - -.. image:: https://github.com/secure-systems-lab/securesystemslib/workflows/Run%20Securesystemslib%20tests/badge.svg - :target: https://github.com/secure-systems-lab/securesystemslib/actions?query=workflow%3A%22Run+Securesystemslib+tests%22+branch%3Amain - - - -A library that provides cryptographic and general-purpose functions for Secure -Systems Lab projects at NYU. The routines are general enough to be usable by -other projects. - -Overview -++++++++ - -securesystemslib supports public-key and general-purpose cryptography, such as -`ECDSA -`_, -`Ed25519 `_, `RSA -`_, SHA256, SHA512, etc. -Most of the cryptographic operations are performed by the `cryptography -`_ and `PyNaCl -`_ libraries, but verification of Ed25519 -signatures can be done in pure Python. - -The `cryptography` library is used to generate keys and signatures with the -ECDSA and RSA algorithms, and perform general-purpose cryptography such as -encrypting keys. The PyNaCl library is used to generate Ed25519 keys and -signatures. PyNaCl is a Python binding to the Networking and Cryptography -Library. For key storage, RSA keys may be stored in PEM or JSON format, and -Ed25519 keys in JSON format. Generating, importing, and loading cryptographic -key files can be done with functions available in securesystemslib. - -securesystemslib also provides an interface to the `GNU Privacy Guard (GPG) -`_ command line tool, with functions to create RSA and DSA -signatures using private keys in a local gpg keychain; to export the -corresponding public keys in a *pythonic* format; and to verify the created -signatures using the exported keys. The latter does not require the gpg command -line tool to be installed, instead the `cryptography` library is used. - -Installation -++++++++++++ - -:: - - $ pip install securesystemslib - - -The default installation only supports Ed25519 keys and signatures (in pure -Python). Support for RSA, ECDSA, and E25519 via the `cryptography` and -`PyNaCl` libraries is available by installing the `crypto` and `pynacl` extras: - -:: - - $ pip install securesystemslib[crypto] - $ pip install securesystemslib[pynacl] - -Usage -++++++++++++ - -Create RSA Keys -~~~~~~~~~~~~~~~ - -Note: In the instructions below, lines that start with *>>>* denote commands -that should be entered by the reader, *#* begins the start of a comment, and -text without prepended symbols is the output of a command. - -:: - - >>> from securesystemslib.interface import * - - # The following function creates an RSA key pair, where the private key is - # saved to "rsa_key1" and the public key to "rsa_key1.pub" (both saved to - # the current working directory). A full directory path may be specified - # instead of saving keys to the current working directory. If specified - # directories do not exist, they will be created. - >>> generate_and_write_rsa_keypair( - password="password", filepath="rsa_key1", bits=2048) - - # If the key length is unspecified, it defaults to 3072 bits. A length of - # less than 2048 bits raises an exception. A similar function is available - # to supply a password on the prompt. If an empty password is entered, the - # private key is saved unencrypted. - >>> generate_and_write_rsa_keypair_with_prompt("rsa_key2") - enter password to encrypt private key file '/path/to/rsa_key2' - (leave empty if key should not be encrypted): - Confirm: - - -The following four key files should now exist: - -1. rsa_key1 -2. rsa_key1.pub -3. rsa_key2 -4. rsa_key2.pub - -Import RSA Keys -~~~~~~~~~~~~~~~ - -:: - - # Continuing from the previous section . . . - - # Import an existing public key. - >>> public_rsa_key1 = import_rsa_publickey_from_file("rsa_key1.pub") - - # Import an existing private key. If your private key is encrypted, - # which it should be, you either have to pass a 'password' or enter one - # on the prompt. - >>> private_rsa_key1 = import_rsa_privatekey_from_file("rsa_key1", password="some passphrase") - # OR: - >>> private_rsa_key1 = import_rsa_privatekey_from_file("rsa_key1", prompt=True) - enter password to decrypt private key file '/path/to/rsa_key1' - (leave empty if key not encrypted): - -**import_rsa_privatekey_from_file()** raises a -*securesystemslib.exceptions.CryptoError* exception if the key / password is -invalid: - -:: - - securesystemslib.exceptions.CryptoError: RSA (public, private) tuple cannot - be generated from the encrypted PEM string: Bad decrypt. Incorrect password? - -Note: The specific message provided by the exception might differ depending on -which cryptography library is used. - -Create and Import Ed25519 Keys -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - # Continuing from the previous section . . . - - # The same generation and import functions as for rsa keys exist for ed25519 - >>> generate_and_write_ed25519_keypair_with_prompt('ed25519_key') - enter password to encrypt private key file '/path/to/ed25519_key' - (leave empty if key should not be encrypted): - Confirm: - - # Import the Ed25519 public key just created . . . - >>> public_ed25519_key = import_ed25519_publickey_from_file('ed25519_key.pub') - - # and its corresponding private key. - >>> private_ed25519_key = import_ed25519_privatekey_from_file('ed25519_key', prompt=True) - enter password to decrypt private key file '/path/to/ed25519_key' - (leave empty if key should not be encrypted): - -Create and Import ECDSA Keys -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - # The same generation and import functions as for rsa and ed25519 keys - # exist for ecdsa - >>> generate_and_write_ecdsa_keypair_with_prompt('ecdsa_key') - enter password to decrypt private key file '/path/to/ecdsa_key' - (leave empty if key should not be encrypted): - - >>> public_ecdsa_key = import_ecdsa_publickey_from_file('ecdsa_key.pub') - >>> private_ecdsa_key = import_ecdsa_privatekey_from_file('ecdsa_key', prompt=True) - enter password to decrypt private key file '/path/to/ecdsa_key' - (leave empty if key should not be encrypted): - -Generate ECDSA, Ed25519, and RSA Signatures -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Note: Users may also access the crypto functions directly to perform -cryptographic operations. - -:: - - >>> from securesystemslib.keys import * - - >>> data = b'The quick brown fox jumps over the lazy dog' - >>> ed25519_key = generate_ed25519_key() - >>> signature = create_signature(ed25519_key, data) - >>> rsa_key = generate_rsa_key(2048) - >>> signature = create_signature(rsa_key, data) - >>> ecdsa_key = generate_ecdsa_key() - >>> signature = create_signature(ecdsa_key, data) - - -Verify ECDSA, Ed25519, and RSA Signatures -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - # Continuing from the previous sections . . . - - >>> data = b'The quick brown fox jumps over the lazy dog' - >>> ed25519_key = generate_ed25519_key() - >>> signature = create_signature(ed25519_key, data) - >>> verify_signature(ed25519_key, signature, data) - True - >>> verify_signature(ed25519_key, signature, 'bad_data') - False - >>> rsa_key = generate_rsa_key() - >>> signature = create_signature(rsa_key, data) - >>> verify_signature(rsa_key, signature, data) - True - >>> ecdsa_key = generate_ecdsa_key() - >>> signature = create_signature(ecdsa_key, data) - >>> verify_signature(ecdsa_key, signature, data) - True - - -Miscellaneous functions -~~~~~~~~~~~~~~~~~~~~~~~ - -**create_rsa_encrypted_pem()** - -:: - - # Continuing from the previous sections . . . - - >>> rsa_key = generate_rsa_key() - >>> private = rsa_key['keyval']['private'] - >>> passphrase = 'secret' - >>> encrypted_pem = create_rsa_encrypted_pem(private, passphrase) - -**import_rsakey_from_public_pem()** - -:: - - >>> rsa_key = generate_rsa_key() - >>> public = rsa_key['keyval']['public'] - >>> rsa_key2 = import_rsakey_from_public_pem(public) - - -**import_rsakey_from_pem()** - -:: - - >>> rsa_key = generate_rsa_key() - >>> public = rsa_key['keyval']['public'] - >>> private = rsa_key['keyval']['private'] - >>> rsa_key2 = import_rsakey_from_pem(public) - >>> rsa_key3 = import_rsakey_from_pem(private) - - -**extract_pem()** - -:: - - >>> rsa_key = generate_rsa_key() - >>> private_pem = extract_pem(rsakey['keyval']['private'], private_pem=True) - >>> public_pem = extract_pem(rsakey['keyval']['public'], private_pem=False) - - -**encrypt_key()** - -:: - - >>> ed25519_key = generate_ed25519_key() - >>> password = 'secret' - >>> encrypted_key = encrypt_key(ed25519_key, password) - - -**decrypt_key()** - -:: - - >>> ed25519_key = generate_ed25519_key() - >>> password = 'secret' - >>> encrypted_key = encrypt_key(ed25519_key, password) - >>> decrypted_key = decrypt_key(encrypted_key.encode('utf-8'), password) - >>> decrypted_key == ed25519_key - True - - -**create_rsa_encrypted_pem()** - -:: - - >>> rsa_key = generate_rsa_key() - >>> private = rsa_key['keyval']['private'] - >>> passphrase = 'secret' - >>> encrypted_pem = create_rsa_encrypted_pem(private, passphrase) - - -**is_pem_public()** - -:: - - >>> rsa_key = generate_rsa_key() - >>> public = rsa_key['keyval']['public'] - >>> private = rsa_key['keyval']['private'] - >>> is_pem_public(public) - True - >>> is_pem_public(private) - False - - -**is_pem_private()** - -:: - - >>> rsa_key = generate_rsa_key() - >>> private = rsa_key['keyval']['private'] - >>> public = rsa_key['keyval']['public'] - >>> is_pem_private(private) - True - >>> is_pem_private(public) - False - - -**import_ecdsakey_from_private_pem()** - -:: - - >>> ecdsa_key = generate_ecdsa_key() - >>> private_pem = ecdsa_key['keyval']['private'] - >>> ecdsa_key2 = import_ecdsakey_from_private_pem(private_pem) - - -**import_ecdsakey_from_public_pem()** - -:: - - >>> ecdsa_key = generate_ecdsa_key() - >>> public = ecdsa_key['keyval']['public'] - >>> ecdsa_key2 = import_ecdsakey_from_public_pem(public) - - -**import_ecdsakey_from_pem()** - -:: - - >>> ecdsa_key = generate_ecdsa_key() - >>> private_pem = ecdsa_key['keyval']['private'] - >>> ecdsa_key2 = import_ecdsakey_from_pem(private_pem) - >>> public_pem = ecdsa_key['keyval']['public'] - >>> ecdsa_key2 = import_ecdsakey_from_pem(public_pem) - - - - -GnuPG interface -~~~~~~~~~~~~~~~ - -Signature creation and public key export requires installation of the `gpg` or -`gpg2` command line tool, which may be downloaded from -`https://gnupg.org/download `_. -It is also needed to generate the supported RSA or DSA signing keys (see `gpg` man -pages for detailed instructions). Sample keys are available in a test keyring -at `tests/gpg_keyrings/rsa`, which may be passed to the signing and export -functions using the `homedir` argument (if not passed the default keyring is -used). The GPG client to use can be also specified with the help of environment -variable `GNUPG`. - -:: - - >>> import securesystemslib.gpg.functions as gpg - - >>> data = b"The quick brown fox jumps over the lazy dog" - - >>> signing_key_id = "8465A1E2E0FB2B40ADB2478E18FB3F537E0C8A17" - >>> keyring = "tests/gpg_keyrings/rsa" - - >>> signature = gpg.create_signature(data, signing_key_id, homedir=keyring) - >>> public_key = gpg.export_pubkey(non_default_signing_key, homedir=keyring) - - >>> gpg.verify_signature(signature, public_key, data) - True - -Testing -++++++++++++ - -Testing is done with `tox `_, which can be installed with pip: -:: - - $ pip install tox - - -Secure Systems Library supports multiple versions of Python. -For that reason, the project is tested against multiple virtual environments with different Python versions. -If you run -:: - -$ tox - -this will run all tests creating virtual environments for all python versions described in the *tox.ini* file. - -If you want to run the tests against specific python version, for example Python 3.7, you will use: -:: - -$ tox -e py37 diff --git a/pyproject.toml b/pyproject.toml index fdcaeaa4..493a561d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "securesystemslib" authors = [{name = "https://www.updateframework.com", email = "theupdateframework@googlegroups.com"}] license = {text = "MIT"} description = "A library that provides cryptographic and general-purpose routines for Secure Systems Lab projects at NYU" -readme = "README.rst" +readme = "README.md" keywords = [ "cryptography", "keys", From 2538c3e426ee1ef8d679f327ba5301ab300f2acf Mon Sep 17 00:00:00 2001 From: Martin Vrachev Date: Fri, 1 Sep 2023 17:33:45 +0300 Subject: [PATCH 2/2] Apply Jussi's suggestions improving README Signed-off-by: Martin Vrachev --- README.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f841019f..a78216ee 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,14 @@ [![CI](https://github.com/secure-systems-lab/securesystemslib/workflows/Run%20Securesystemslib%20tests/badge.svg)](https://github.com/secure-systems-lab/securesystemslib/actions?query=workflow%3A%22Run+Securesystemslib+tests%22+branch%3Amain) -A cryptography interface to sign and verify -[TUF](https://theupdateframework.io) and [in-toto](https://in-toto.io) -metadata. +Securesystemslib is a cryptography interface for signing and verifying digital +signatures. It is developed for the [TUF](https://theupdateframework.io) and +[in-toto](https://in-toto.io) projects: the key and signature containers are +compatible with metadata formats from those projects. + +Under the hood, Securesystemslib can use various digital signing systems +(e.g. [cryptography](https://pypi.org/project/cryptography/), PIV hardware keys +and multiple cloud-based key management systems). ## Installation @@ -18,6 +23,11 @@ signature creation, `securesystemslib` can be installed with *extras*. See pip install securesystemslib[crypto] ``` +```bash +# ...or with HSM (e.g. Yubikey) support +pip install securesystemslib[hsm] +``` + ## Usage [python-securesystemslib.readthedocs.io](https://python-securesystemslib.readthedocs.io) @@ -25,8 +35,7 @@ pip install securesystemslib[crypto] - Questions and discussions: [`#securesystemslib-python`](https://cloud-native.slack.com/archives/C05PF3GA7AL) on [CNCF Slack](https://communityinviter.com/apps/cloud-native/cncf) -- Security issues: [*Draft a new security - advisory*](https://github.com/secure-systems-lab/securesystemslib/security/advisories/new) +- Security issues: [*Report a vulnerability*](https://github.com/secure-systems-lab/securesystemslib/security/advisories/new) - Other issues and requests: [*Open a new issue*](https://github.com/secure-systems-lab/securesystemslib/issues/new)