Skip to content

Commit

Permalink
Signing and validation now works
Browse files Browse the repository at this point in the history
Todo: export to file
  • Loading branch information
scheibling committed Dec 31, 2023
1 parent fc2d5dc commit 6101b0f
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 27 deletions.
14 changes: 7 additions & 7 deletions make_signature.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/bin/bash
ssh-keygen -t rsa -b 4096 -f id_rsa -N ''
ssh-keygen -t ecdsa -f id_ecdsa -N ''
ssh-keygen -t ed25519 -f id_ed25519 -N ''
echo "Hello World" | tee rsa.txt | tee ecdsa.txt | tee ed25519.txt
ssh-keygen -t rsa -b 4096 -f testkeys/id_rsa -N ''
ssh-keygen -t ecdsa -f testkeys/id_ecdsa -N ''
ssh-keygen -t ed25519 -f testkeys/id_ed25519 -N ''
echo "Hello World" | tee testkeys/rsa.txt | tee testkeys/ecdsa.txt | tee testkeys/ed25519.txt

ssh-keygen -Y sign -n hello@world -f id_rsa rsa.txt
ssh-keygen -Y sign -n hello@world -f id_ecdsa ecdsa.txt
ssh-keygen -Y sign -n hello@world -f id_ed25519 ed25519.txt
ssh-keygen -Y sign -n hello@world -f testkeys/id_rsa testkeys/rsa.txt
ssh-keygen -Y sign -n hello@world -f testkeys/id_ecdsa testkeys/ecdsa.txt
ssh-keygen -Y sign -n hello@world -f testkeys/id_ed25519 testkeys/ed25519.txt
3 changes: 2 additions & 1 deletion src/sshkey_tools/cert.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ def get(self, name: str, default=None):
if field:
if isinstance(field, type):
return field.DEFAULT
return field.value
if getattr(field, "value", False):
return field.value
return field

def getattrs(self) -> tuple:
Expand Down
38 changes: 31 additions & 7 deletions src/sshkey_tools/signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,19 @@ class SSHSignature:
"""
General class for SSH Signatures, used for loading and parsing.
"""
data: bytes = None

def __init__(
self, signer_privkey: _KEY.PrivateKey = None,
fields: SignatureFieldset = SignatureFieldset
):
self.fields = fields() if isinstance(fields, type) else fields

if isinstance(signer_privkey, type) and signer_privkey is not None:
if signer_privkey is not None:
self.fields.replace_field(
"signature", _FIELD.SignatureField.from_object(signer_privkey)
)
)
self.fields.replace_field("public_key", signer_privkey.public_key)

@classmethod
def from_file(cls, path: str, encoding: str = 'none') -> "SSHSignature":
Expand Down Expand Up @@ -137,7 +140,23 @@ def get_signable(self, data: Union[str, bytes]) -> bytes:
)

return bytes(self.fields) + _FIELD.StringField.encode(hash)

def get_signable_file(self, path: str) -> bytes:
"""
Loads the signable content from a file.
Will be loaded as bytes without encoding.
Args:
path (str): Path to the file
Returns:
bytes: The signable data from the file
"""
with open(path, 'rb') as f:
data = f.read()

return self.get_signable(data)

def __str__(self) -> str:
table = PrettyTable(["Field", "Value"])

Expand All @@ -163,14 +182,19 @@ def verify(
self, data, public_key: _KEY.PublicKey = None, raise_on_error: bool = False
) -> bool:
if not public_key:
public_key = self.get('public_key').value
public_key = self.fields.get('public_key', None)

public_key.verify(
self.get_signable(data),
self.fields.signature.value
)



print()

def sign(self, data: Union[str, bytes]):
signable = self.get_signable(data)
self.fields.signature.sign(signable)

def sign_file(self, path: str):
signable = self.get_signable_file(path)
self.fields.signature.sign(signable)


49 changes: 37 additions & 12 deletions validate_signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,27 @@
signatures as _S
)

# Load public and private keys
rsa_priv = _K.PrivateKey.from_file('testkeys/id_rsa')
ecdsa_priv = _K.PrivateKey.from_file('testkeys/id_ecdsa')
ed25519_priv = _K.PrivateKey.from_file('testkeys/id_ed25519')
rsa_pub = rsa_priv.public_key
ecdsa_pub = ecdsa_priv.public_key
ed25519_pub = ed25519_priv.public_key

# Validate files created with ssh-keygen (WORKS!)
rsa_pub = _K.PublicKey.from_file('testkeys/id_rsa.pub')
ecdsa_pub = _K.PublicKey.from_file('testkeys/id_ecdsa.pub')
ed25519_pub = _K.PublicKey.from_file('testkeys/id_ed25519.pub')

# Load externally created signatures
rsa_sign = _S.SSHSignature.from_file('testkeys/rsa.txt.sig')
ecdsa_sign = _S.SSHSignature.from_file('testkeys/ecdsa.txt.sig')
ed25519_sign = _S.SSHSignature.from_file('testkeys/ed25519.txt.sig')

rsa_data = open('rsa.txt', 'rb').read()
ecdsa_data = open('ecdsa.txt', 'rb').read()
ed25519_data = open('ed25519.txt', 'rb').read()
# Load the data used for the signatures
rsa_data = open('testkeys/rsa.txt', 'rb').read()
ecdsa_data = open('testkeys/ecdsa.txt', 'rb').read()
ed25519_data = open('testkeys/ed25519.txt', 'rb').read()

rsa_signable = rsa_sign.get_signable(rsa_data)
ecdsa_signable = ecdsa_sign.get_signable(ecdsa_data)
ed25519_signable = ed25519_sign.get_signable(ed25519_data)
rsa_signable = rsa_sign.get_signable_file('testkeys/rsa.txt')
ecdsa_signable = ecdsa_sign.get_signable_file('testkeys/ecdsa.txt')
ed25519_signable = ed25519_sign.get_signable_file('testkeys/ed25519.txt')

try:
rsa_pub.verify(rsa_signable, rsa_sign.fields.signature.value)
Expand All @@ -38,4 +42,25 @@
except:
print("Ed25519 validation failed")

print()


try:
rsasig = _S.SSHSignature(rsa_priv)
rsasig.sign(rsa_data)
rsa_pub.verify(rsasig.get_signable(rsa_data), rsasig.fields.signature.value)
except:
print("RSA validation after signing failed")

try:
ecdsasig = _S.SSHSignature(ecdsa_priv)
ecdsasig.sign(ecdsa_data)
ecdsa_pub.verify(ecdsasig.get_signable(ecdsa_data), ecdsasig.fields.signature.value)
except:
print("ECDSA validation after signing failed")

try:
ed25519sig = _S.SSHSignature(ed25519_priv)
ed25519sig.sign(ed25519_data)
ed25519_pub.verify(ed25519sig.get_signable(ed25519_data), ed25519sig.fields.signature.value)
except:
print("Ed25519 validation after signing failed")

0 comments on commit 6101b0f

Please sign in to comment.