Skip to content

Commit 4dab3cf

Browse files
committed
Fixed linter errors, formatted code, added comments
1 parent 1fdee4c commit 4dab3cf

2 files changed

Lines changed: 94 additions & 7 deletions

File tree

src/sshkey_tools/exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,9 @@ class DeprecatedClassCalled(ValueError):
113113
"""
114114
Raised when trying to instantiate a deprecated class
115115
"""
116+
117+
118+
class InvalidHashAlgorithmException(ValueError):
119+
"""
120+
Raised when the hash algorithm specified is not supported
121+
"""

src/sshkey_tools/signatures.py

Lines changed: 88 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
# Format:
1+
"""SSH Data signature implementation
2+
3+
Raises:
4+
_EX.InvalidDataException: Data is invalid
5+
_EX.InvalidHashAlgorithmException: The hash algorithm is invalid
6+
_EX.InvalidCertificateFieldException: The certificate field contains invalid data
7+
"""
28

9+
# Format:
310
# byte[6] MAGIC_PREAMBLE (SSHSIG)
411
# uint32 SIG_VERSION (0x01)
512
# string publickey
@@ -8,8 +15,8 @@
815
# string hash_algorithm
916
# string signature
1017
from base64 import b64decode, b64encode
11-
from .cert import Fieldset, dataclass, Union
1218
from prettytable import PrettyTable
19+
from .cert import Fieldset, dataclass, Union
1320
from .utils import concat_to_bytestring, ensure_bytestring
1421
from . import fields as _FIELD, keys as _KEY, exceptions as _EX, utils as _U
1522

@@ -40,6 +47,11 @@ class SignatureFieldset(Fieldset):
4047
signature: _FIELD.SignatureField = _FIELD.SignatureField.factory
4148

4249
def __bytes__(self):
50+
"""Returns the data as a bytestring for encoding
51+
52+
Returns:
53+
data: Data bytes
54+
"""
4355
return concat_to_bytestring(
4456
bytes(self.magic_preamble),
4557
bytes(self.namespace),
@@ -48,6 +60,11 @@ def __bytes__(self):
4860
)
4961

5062
def format_pubkey(self):
63+
"""Format the public key and strip and extra data
64+
65+
Returns:
66+
key: The formatted public key
67+
"""
5168
pubkey = self.public_key.value.to_string().split(" ")
5269

5370
return _FIELD.StringField.encode(
@@ -60,6 +77,11 @@ def format_pubkey(self):
6077
# ))
6178

6279
def bytes_out(self):
80+
"""Generates the output bytes for the finished signature
81+
82+
Returns:
83+
output: The complete signature
84+
"""
6385
return concat_to_bytestring(
6486
bytes(self.magic_preamble),
6587
bytes(self.sig_version),
@@ -155,7 +177,8 @@ def from_file(cls, path: str, encoding: str = "none") -> "SSHSignature":
155177
156178
Args:
157179
path (str): The path to the file
158-
encoding (str, optional): The encoding of the file. None will load the byte content directly. Defaults to 'utf-8'.
180+
encoding (str, optional): The encoding of the file. None will load the byte
181+
content directly. Defaults to 'utf-8'.
159182
160183
Returns:
161184
SSHSignature: SSH Signature Object
@@ -212,17 +235,17 @@ def get_signable(self, data: Union[str, bytes]) -> bytes:
212235
Returns:
213236
bytes: The signable data
214237
"""
215-
hash = b""
238+
hash_kind = b""
216239
if self.fields.hash_algorithm.value == "sha256":
217-
hash = _U.sha256_hash(ensure_bytestring(data))
240+
hash_kind = _U.sha256_hash(ensure_bytestring(data))
218241
elif self.fields.hash_algorithm.value == "sha512":
219-
hash = _U.sha512_hash(ensure_bytestring(data))
242+
hash_kind = _U.sha512_hash(ensure_bytestring(data))
220243
else:
221244
raise _EX.InvalidHashAlgorithmException(
222245
f"Unknown hash algorithm {self.fields.hash_algorithm}"
223246
)
224247

225-
return bytes(self.fields) + _FIELD.StringField.encode(hash)
248+
return bytes(self.fields) + _FIELD.StringField.encode(hash_kind)
226249

227250
def get_signable_file(self, path: str) -> bytes:
228251
"""
@@ -249,12 +272,32 @@ def __str__(self) -> str:
249272
return str(table)
250273

251274
def get(self, field: str):
275+
"""Get the contents of a field
276+
277+
Args:
278+
field (str): Field name
279+
280+
Raises:
281+
_EX.InvalidCertificateFieldException: Invalid field name
282+
283+
Returns:
284+
data: The field data
285+
"""
252286
if field in self.fields.getattrs():
253287
return self.fields.get(field, None)
254288

255289
raise _EX.InvalidCertificateFieldException(f"Unknown field {field}")
256290

257291
def set(self, field: str, data):
292+
"""Sets the contents of a field
293+
294+
Args:
295+
field (str): Field name
296+
data (any): Data for the field
297+
298+
Raises:
299+
_EX.InvalidCertificateFieldException: Invalid field name
300+
"""
258301
if field in self.fields.getattrs():
259302
self.fields.set(field, data)
260303
return
@@ -264,20 +307,53 @@ def set(self, field: str, data):
264307
def verify(
265308
self, data, public_key: _KEY.PublicKey = None, raise_on_error: bool = False
266309
) -> bool:
310+
"""Verify a SSH Signature
311+
312+
Args:
313+
data (bytes): The signed data
314+
public_key (_KEY.PublicKey, optional): The public key to use to verify
315+
the signature. If none are specified, the public key from the
316+
signature will be used. Defaults to None.
317+
raise_on_error (bool, optional): Whether to raise an exception on
318+
verification failure. Defaults to False.
319+
320+
Returns:
321+
bool: True if the signature is valid, False otherwise.
322+
"""
267323
if not public_key:
268324
public_key = self.fields.get("public_key", None)
269325

326+
if raise_on_error and not public_key.verify(
327+
self.get_signable(data), self.fields.signature.value
328+
):
329+
raise _EX.InvalidSignatureException("Signature verification failed")
330+
270331
public_key.verify(self.get_signable(data), self.fields.signature.value)
271332

272333
def sign(self, data: Union[str, bytes]):
334+
"""Signs the data
335+
336+
Args:
337+
data (Union[str, bytes]): The data to sign
338+
"""
273339
signable = self.get_signable(data)
274340
self.fields.signature.sign(signable)
275341

276342
def sign_file(self, path: str):
343+
"""Signs a file at a given path
344+
345+
Args:
346+
path (str): The path to the file to sign
347+
"""
277348
signable = self.get_signable_file(path)
278349
self.fields.signature.sign(signable)
279350

280351
def to_string(self):
352+
"""Converts the signature data to the text-based signature format
353+
354+
Returns:
355+
string: The encoded signature data
356+
"""
281357
content = self.fields.bytes_out()
282358
content = b64encode(content)
283359
file_content = b"-----BEGIN SSH SIGNATURE-----\n"
@@ -289,5 +365,10 @@ def to_string(self):
289365
return file_content
290366

291367
def to_file(self, path: str):
368+
"""Save the content of the signature to a file
369+
370+
Args:
371+
path (str): The path to the file
372+
"""
292373
with open(path, "wb") as f:
293374
f.write(self.to_string())

0 commit comments

Comments
 (0)