Skip to content

Commit

Permalink
Removed DSA Support
Browse files Browse the repository at this point in the history
  • Loading branch information
Lars Scheibling authored and scheibling committed Jun 7, 2023
1 parent 375427f commit b21f981
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 207 deletions.
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
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

0 comments on commit b21f981

Please sign in to comment.