Skip to content

Commit 955a38b

Browse files
committed
Add imported "change nonce" warning
1 parent d2ee39a commit 955a38b

3 files changed

Lines changed: 39 additions & 1 deletion

File tree

src/sshkey_tools/cert.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ def decode(cls, data: bytes) -> Tuple["CertificateHeader", bytes]:
166166

167167
public_key, data = getattr(_FIELD, target_class[1]).from_decode(data)
168168
cl_instance.public_key = public_key
169+
170+
cl_instance.nonce._was_imported = True
171+
cl_instance.nonce._imported_as = cl_instance.get("nonce")
169172

170173
return cl_instance, data
171174

src/sshkey_tools/fields.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,15 @@ class NonceField(BytestringField):
777777

778778
DEFAULT = generate_secure_nonce
779779
DATA_TYPE = (str, bytes)
780+
781+
_was_imported = bool
782+
_imported_as = (str, bytes)
783+
784+
def was_imported(self) -> bool:
785+
"""
786+
Returns whether the certificate was imported or not
787+
"""
788+
return isinstance(self._was_imported, bool) and self._was_imported
780789

781790
def __validate_value__(self) -> Union[bool, Exception]:
782791
"""
@@ -792,6 +801,11 @@ def __validate_value__(self) -> Union[bool, Exception]:
792801
"Expected a nonce of at least 32 bytes"
793802
)
794803

804+
if self.was_imported() and self._imported_as == self.value:
805+
print("""[Notice] This certificate was imported. Before re-signing,"""
806+
""" it is recommended to change the nonce to a new value to """
807+
"""protect the integrity of the private key in the long run.""")
808+
795809
return True
796810

797811

tests/test_certificates.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ def test_cert_type_assignment(self):
561561
self.assertIsInstance(ecdsa_cert, _CERT.EcdsaCertificate)
562562
self.assertIsInstance(ed25519_cert, _CERT.Ed25519Certificate)
563563

564-
def assertCertificateCreated(self, sub_type, ca_type):
564+
def getReloadedCertificate(self, sub_type, ca_type):
565565
sub_pubkey = getattr(self, f"{sub_type}_user")
566566
ca_privkey = getattr(self, f"{ca_type}_ca")
567567

@@ -590,6 +590,11 @@ def assertCertificateCreated(self, sub_type, ca_type):
590590
reloaded_cert = _CERT.SSHCertificate.from_file(
591591
f"tests/certificates/{sub_type}_{ca_type}-cert.pub"
592592
)
593+
594+
return certificate, reloaded_cert
595+
596+
def assertCertificateCreated(self, sub_type, ca_type):
597+
certificate, reloaded_cert = self.getReloadedCertificate(sub_type, ca_type)
593598

594599
self.assertEqual(certificate.get_signable(), reloaded_cert.get_signable())
595600

@@ -602,6 +607,22 @@ def test_certificate_creation(self):
602607
)
603608
)
604609
self.assertCertificateCreated(user_type, ca_type)
610+
611+
def test_certificate_import_sets_nonce_imported(self):
612+
for ca_type in CERTIFICATE_TYPES:
613+
for user_type in CERTIFICATE_TYPES:
614+
print(
615+
"Testing certificate import for {} CA and {} user".format(
616+
ca_type, user_type
617+
)
618+
)
619+
620+
cert, reloaded_cert = self.getReloadedCertificate(user_type, ca_type)
621+
622+
self.assertFalse(cert.header.nonce.was_imported())
623+
self.assertTrue(reloaded_cert.header.nonce.was_imported())
624+
625+
605626

606627

607628
if __name__ == "__main__":

0 commit comments

Comments
 (0)