Skip to main content

sshkey-tools (Work in progress)

Python and CLI tools for managing OpenSSH keypairs and certificates

Usage

sshkey --help

Table of Contents

Python Usage

Private keys

Generalized class

from sshkey_tools.keys import PrivateKey

# Load from keyfile (Returns sshkey_tools.keys.RSAPrivateKey, etc.)
key = PrivateKey.from_file('id_rsa')

# Load from string/file contents (Returns sshkey_tools.keys.RSAPrivateKey for RSA, etc.)
key = PrivateKey.from_string('-----Begin.......... End-----')

# Load from key bytes (inner bytes, without comment and key type prefix)
key = PrivateKey.from_bytes(b'%x00%x00......')

# If the key is password protected, set the password variable
key = PrivateKey.from_...('', password='abc123')

Specific key classes

In addition to specifically loading e.g. an RSA key with the from_bytes, from_string or from_file methods above, you can also specifically load a key type with that function with e.g. RSAPrivateKey.from_file('filename')

from sshkey_tools.keys import (
    RSAPrivateKey,
    DSAPrivateKey,
    ECDSAPrivateKey,
    ED25519PrivateKey
)


# Generate new RSA key
key = RSAPrivateKey.generate(
    key_size=4096,
    public_exponent=65537
)

# Generate new DSA/DSS key
key = DSAPrivateKey.generate(
    key_size=4096,
)

# Generate new ECDSA key
key = ECDSAPrivateKey.generate(
    curve=ECDSA_CURVES.SECP384R1()
)

# Generate new ED25519 key
key = ED25519PrivateKey.generate()

# Load RSA key from numbers
key = RSAPrivateKey.from_numbers(
    n=123123,
    e=123123,
    p=123123,
    q=123123,    # Optional
    d=123123,    # Optional
    dmp1=123123, # Optional
    dmq1=123123, # Optional
    iqmp=123123  # Optional
)

# Load DSA key from numbers
key = DSAPrivateKey.from_numbers(
    p=123123,
    q=123123,
    g=123123,
    y=123123,
    x=123123
)

# Load ECDSA key from numbers
key = ECDSAPrivateKey.from_numbers(
    private_number=123123,
    x=123123,
    y=123123,
    curve=ECDSA_CURVES.SECP384R1()
)


# ED25519 keys don't support loading from numbers

Exporting private keys

The export class looks the same on all the PrivateKey-classes, the example below will use the general PrivateKey class but everything works the same for the specific classes

from sshkey_tools.keys import FORMAT

# key is an instance of PrivateKey or any of its subclasses

key_str = key.to_string(FORMAT.OpenSSH)
print(key_str)
"""
-----BEGIN OPENSSH PRIVATE KEY-----
ABCDEFG.......
-----END OPENSSH PRIVATE KEY-----
"""

# Produces the same output as above, but writes it directly to file
key.to_file('samplekey', FORMAT.OpenSSH)

key_bin = key.to_bytes(FORMAT.BARE)
print(key_bin)
b"""
%x0f%x00%x12.......
"""

Public Keys

Generalized class

from sshkey_tools.keys import PrivateKey, PublicKey

# Load from keyfile (Returns sshkey_tools.keys.RSAPrivateKey, etc.)
public_key = PublicKey.from_file('id_rsa.pub')

# Load from string/file contents (Returns sshkey_tools.keys.RSAPublicKey for RSA, etc.)
public_key = PublicKey.from_string('ssh-rsa AA.......... someone@somehost')

# Load from key bytes (inner bytes, without comment and key type prefix)
public_key = PublicKey.from_bytes(b'%x00%x00......')

# Load public key from private key class 
private_key = PrivateKey.from_file('id_rsa')
public_key = private_key.public_key()

Specific key classes

In addition to specifically loading e.g. an RSA key with the from_bytes, from_string or from_file methods above, you can also specifically load a key type with that function with e.g. RSAPrivateKey.from_file('filename')

from sshkey_tools.keys import (
    RSAPublicKey,
    DSAPublicKey,
    ECDSAPublicKey,
    ED25519PublicKey
)

# Load RSA public key from numbers
key = RSAPublicKey.from_numbers(
    n=123123,
    e=123123
)

# Load DSA public key from numbers
key = DSAPublicKey.from_numbers(
    p=123123,
    q=123123,
    g=123123,
    y=123123
)

# Load ECDSA public key from numbers
key = ECDSAPublicKey.from_numbers(
    x=123123,
    y=123123,
    curve=ECDSA_CURVES.SECP384R1()
)


# ED25519 keys don't support loading from numbers

Exporting public keys

# pubkey can be an instance of any of the PublicKeyClass children

Certificates

Generalized classes

from sshkey_tools.cert import SSHCertificate

## Existing certificates

# Load from file (Returns specific class, e.g. sshkey_tools.cert.RSACertificate)
certificate = SSHCertificate.from_file('id_rsa-cert.pub')

# Load from string/file contents
certificate = SSHCertificate.from_string('ssh-rsa-cert-v01@openssh.com AA.......... someone@somehost')

# Load from key bytes (inner bytes, without comment and type prefix)
certificate = SSHCertificate.from_bytes(b'%x00%x00.......')

## New certificates


# Create a blank certificate for a specific public key, automatically returns the right certificate class
certificate = SSHCertificate.from_public(PublicKeyClass pubkey)

# Create a certificate from a dictionary with values
# The only mandatory value at this stage is the public_key that is to be signed
cert_val = {
    "serial": "abcdef",
    "key_id": 123123,
    "public_key": pubkey
}

certificate = SSHCertificate.from_dict(cert_val)

Specific certificate classes

from sshkey_tools.cert import (
    RSACertificate,
    DSACertificate,
    ECDSACertificate,
    ED25519Certificate
)

The signing process

The signing process consists of three main steps

  1. Create a certificate object for a public key
  2. Add attributes
  3. Sign the certificate with your CA

Create a certificate for a public key

from sshkey_tools.keys import PublicKey, PrivateKey
from sshkey_tools.cert import SSHCertificate

# Load the client public key and the CA private key
client_pubkey = PublicKey.from_file('client.pub')
ca_privkey = PrivateKey.from_file('ca_key')

# Create a blank certificate object from the client public key
# The certificate type is defined by the client key, not the CA
certificate = SSHCertificate.from_public(client_pubkey)

# Add the required attributes to the key
# All attributes can be set either by set_[name](value) or via the set_array function
certificate.set_type(USER)
certificate.set_array(
    "serial": "abc123",
    "key_id": 123,
    "principals": [
        'webservers',
        'database'
    ]
    .....
)

# Once done, make sure the certificate has all the required attributes
# Then, feed the CA Private key to the sign function
if certificate.can_sign():
    certificate.sign(ca_privkey)

# You can check if the certificate has been successfully signed with the is_signature_valid() function
# Then, export the certificate to file, string or bytes
if certificate.is_signature_valid():
    # If no filename is provided, the certificate is saved as [user_pubkey_name]-cert.pub
    certificate.to_file('id_rsa-cert.pub')
    cert_string = certificate.to_string()
    cert_bytes = certificate.to_bytes()

TODO

  • PrivateKey.to_file/string/bytes
  • PublicKey.to_file/string/bytes
  • Certificate.to_file/string/bytes
  • Exceptions.py

Metadata

Release files for sshkey-tools 0.4.post2384544826

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sshkey-tools 0.4.post2384544826
File Size Uploaded
sshkey-tools-0.4.post2384544826.tar.gz 34.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sshkey-tools 0.4.post2384544826
File Interpreter ABI Platform
sshkey_tools-0.4.post2384544826-py3-none-any.whl Python 3 none any Details

Total release size: 68.7 kB

Release files / sshkey-tools-0.4.post2384544826.tar.gz

Download URL sshkey-tools-0.4.post2384544826.tar.gz
Size 34.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8ed1c8893286a4e577cbab641a6641ce31279f83b2776f09d885ce81432d99b4
BLAKE2b-256 checksum
How to use checksums
2e00ff589c7f2f083a3cb4d9f601f5f2597761034f45275dbc2bdafd6ae2ceb1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.0 CPython/3.10.4

Release files / sshkey_tools-0.4.post2384544826-py3-none-any.whl

Download URL sshkey_tools-0.4.post2384544826-py3-none-any.whl
Size 34.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3b334e20f11115364094661c8ff09fd0aa16bf130c0577238bf7119b73b3af87
BLAKE2b-256 checksum
How to use checksums
b956a15056aea15906c79bb5389f09ecd6b86d88300c7daac9c855c3ceb19c01
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.0 CPython/3.10.4
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page