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

Remove dsa support #31

Merged
merged 2 commits into from
Jun 7, 2023
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
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

Python package for managing OpenSSH keypairs and certificates ([protocol.CERTKEYS](https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.certkeys)). Supported functionality includes:

# Notice
## Notice
The DSA algorithm has been deprecated and is removed in pyca/cryptography 41.x, meaning **version 0.9.* of this package will be the last to support DSA keys and certificates** for SSH. If there is any demand to reintroduce DSA support, please open an issue regarding this and we'll look into it.

For now, **0.9.* will be restricted to version <41.1 of the cryptography package** and **0.10 will have its DSA support removed**. We've introduced a deprecation notice in version 0.9.3.

## Background
### Background
The DSA algorithm is considered deprecated and will be removed in a future version. If possible, use RSA, [(ECDSA)](https://billatnapier.medium.com/ecdsa-weakness-where-nonces-are-reused-2be63856a01a) or ED25519 as a first-hand choice.

## Notice from OpenSSH:
### Notice from OpenSSH:
```
OpenSSH 7.0 and greater similarly disable the ssh-dss (DSA) public key algorithm. It too is weak and we recommend against its use. It can be re-enabled using the HostKeyAlgorithms configuration option: sshd_config(5) HostKeyAlgorithms
```
Expand All @@ -19,7 +19,7 @@ OpenSSH 7.0 and greater similarly disable the ssh-dss (DSA) public key algorithm

# Features
### SSH Keys
- Supports RSA, DSA (Note: Deprecated), ECDSA and ED25519 keys
- Supports RSA, ECDSA and ED25519 keys
- Import existing keys from file, string, byte data or [pyca/cryptography](https://github.com/pyca/cryptography) class
- Generate new keys
- Get public key from private keys
Expand All @@ -28,7 +28,7 @@ OpenSSH 7.0 and greater similarly disable the ssh-dss (DSA) public key algorithm
- Generate fingerprint

### OpenSSH Certificates
- Supports RSA, DSA, ECDSA and ED25519 certificates
- Supports RSA, ECDSA and ED25519 certificates
- Import existing certificates from file, string or bytes
- Verify certificate signature against internal or separate public key
- Create new certificates from CA private key and subject public key
Expand Down Expand Up @@ -72,7 +72,6 @@ rm -rf docs/sshkey_tools
# Import the certificate classes
from sshkey_tools.keys import (
RsaPrivateKey,
DsaPrivateKey,
EcdsaPrivateKey,
Ed25519PrivateKey,
EcdsaCurves
Expand All @@ -87,7 +86,8 @@ rsa_priv = RsaPrivateKey.generate()
rsa_priv = RsaPrivateKey.generate(2048)

# Generate DSA keys (since SSH only supports 1024-bit keys, this is the default)
dsa_priv = DsaPrivateKey.generate()
# DEPRECATED
# dsa_priv = DsaPrivateKey.generate()

# Generate ECDSA keys (The default curve is P521)
ecdsa_priv = EcdsaPrivateKey.generate()
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
click
cryptography<41.0.0
cryptography
bcrypt
enum34
PrettyTable
Expand Down
14 changes: 5 additions & 9 deletions src/sshkey_tools/cert.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"[email protected]": ("RsaCertificate", "RsaPubkeyField"),
"[email protected]": ("RsaCertificate", "RsaPubkeyField"),
"[email protected]": ("RsaCertificate", "RsaPubkeyField"),
"[email protected]": ("DsaCertificate", "DsaPubkeyField"),
"[email protected]": (
"EcdsaCertificate",
"EcdsaPubkeyField",
Expand Down Expand Up @@ -579,14 +578,11 @@ class RsaCertificate(SSHCertificate):

class DsaCertificate(SSHCertificate):
"""The DSA Certificate class (DEPRECATED)"""

DEFAULT_KEY_TYPE = "[email protected]"

def __post_init__(self):
"""Display the deprecation notice"""
warnings.warn(
"SSH DSA keys and certificates are deprecated and will be removed in version 0.10 of sshkey-tools",
stacklevel=2,

def __init__(self, *args, **kwargs):
"""DEPRECATED CERTIFICATE CLASS"""
raise _EX.DeprecatedClassCalled(
"DSA certificates are deprecated and have been removed since version 0.10 of sshkey-tools"
)


Expand Down
5 changes: 5 additions & 0 deletions src/sshkey_tools/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,8 @@ class InvalidClassCallException(ValueError):
"""
Raised when trying to instantiate a parent class
"""

class DeprecatedClassCalled(ValueError):
"""
Raised when trying to instantiate a deprecated class
"""
88 changes: 12 additions & 76 deletions src/sshkey_tools/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

from . import exceptions as _EX
from .keys import (
DsaPrivateKey,
DsaPublicKey,
EcdsaPrivateKey,
EcdsaPublicKey,
Ed25519PrivateKey,
Expand Down Expand Up @@ -53,21 +51,18 @@

SUBJECT_PUBKEY_MAP = {
RsaPublicKey: "RsaPubkeyField",
DsaPublicKey: "DsaPubkeyField",
EcdsaPublicKey: "EcdsaPubkeyField",
Ed25519PublicKey: "Ed25519PubkeyField",
}

CA_SIGNATURE_MAP = {
RsaPrivateKey: "RsaSignatureField",
DsaPrivateKey: "DsaSignatureField",
EcdsaPrivateKey: "EcdsaSignatureField",
Ed25519PrivateKey: "Ed25519SignatureField",
}

SIGNATURE_TYPE_MAP = {
b"rsa": "RsaSignatureField",
b"dss": "DsaSignatureField",
b"ecdsa": "EcdsaSignatureField",
b"ed25519": "Ed25519SignatureField",
}
Expand Down Expand Up @@ -727,7 +722,6 @@ class PubkeyTypeField(StringField):
"[email protected]",
"[email protected]",
"[email protected]",
"[email protected]",
"[email protected]",
"[email protected]",
"[email protected]",
Expand Down Expand Up @@ -867,11 +861,8 @@ class DsaPubkeyField(PublicKeyField):
Holds the DSA Public Key for DSA Certificates
"""

DEFAULT = None
DATA_TYPE = DsaPublicKey

@staticmethod
def decode(data: bytes) -> Tuple[DsaPublicKey, bytes]:
def decode(data: bytes):
"""
Decode the certificate field from a byte string
starting with the encoded public key
Expand All @@ -882,12 +873,7 @@ def decode(data: bytes) -> Tuple[DsaPublicKey, bytes]:
Returns:
Tuple[RsaPublicKey, bytes]: The PublicKey field and remainder of the data
"""
p, data = MpIntegerField.decode(data)
q, data = MpIntegerField.decode(data)
g, data = MpIntegerField.decode(data)
y, data = MpIntegerField.decode(data)

return DsaPublicKey.from_numbers(p=p, q=q, g=g, y=y), data
raise _EX.DeprecatedClassCalled("DSA is deprecated, use RSA or ECDSA instead")


class EcdsaPubkeyField(PublicKeyField):
Expand Down Expand Up @@ -1469,16 +1455,13 @@ class DsaSignatureField(SignatureField):
Creates and contains the DSA signature from an DSA Private Key
"""

DEFAULT = None
DATA_TYPE = bytes

def __init__(
self, private_key: DsaPrivateKey = None, signature: bytes = None
) -> None:
super().__init__(private_key, signature)
def __init__(self, *args, **kwargs) -> None:
raise _EX.DeprecatedClassCalled(
"DSA signatures are deprecated and have been removed"
)

@classmethod
def encode(cls, value: bytes):
def encode(cls, value = None):
"""
Encodes the signature to a byte string
Expand All @@ -1488,62 +1471,15 @@ def encode(cls, value: bytes):
Returns:
bytes: The encoded byte string
"""
cls.__validate_type__(value, True)

r, s = decode_dss_signature(value)

return BytestringField.encode(
StringField.encode("ssh-dss")
+ BytestringField.encode(long_to_bytes(r, 20) + long_to_bytes(s, 20))
)
cls()

@staticmethod
def decode(data: bytes) -> Tuple[bytes, bytes]:
"""
Decodes a bytestring containing a signature
Args:
data (bytes): The bytestring starting with the Signature
Returns:
Tuple[ bytes, bytes ]: signature, remainder of the data
"""
signature, data = BytestringField.decode(data)

signature = BytestringField.decode(BytestringField.decode(signature)[1])[0]
r = bytes_to_long(signature[:20])
s = bytes_to_long(signature[20:])

signature = encode_dss_signature(r, s)

return signature, data
def decode(data = None):
DsaSignatureField()

@classmethod
def from_decode(cls, data: bytes) -> Tuple["DsaSignatureField", bytes]:
"""
Creates a signature field class from the encoded signature
Args:
data (bytes): The bytestring starting with the Signature
Returns:
Tuple[ DsaSignatureField, bytes ]: signature, remainder of the data
"""
signature, data = cls.decode(data)

return cls(private_key=None, signature=signature), data

# pylint: disable=unused-argument
def sign(self, data: bytes, **kwargs) -> None:
"""
Signs the provided data with the provided private key
Args:
data (bytes): The data to be signed
"""
self.value = self.private_key.sign(data)
self.is_signed = True

def from_decode(cls, data = None):
cls()

class EcdsaSignatureField(SignatureField):
"""
Expand Down
Loading