Skip to content

Commit

Permalink
Drop legacy signature verification code (DO NOT MERGE!)
Browse files Browse the repository at this point in the history
IMPORTANT NOTE:

- This is a massive breaking change, which I suggest to hold off for
  1.0.0, after the keys refactor is finished.
- The commit is mostly to visualize how much more lightweight the new
  implementation is.
- It might be worth to skim the removed tests, if we are removing any
  interesting cases that we should port to test_signer.
- python-tuf should not be affected, because it already uses the signer API
- in-toto definitely is (see in-toto/in-toto#532)

Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
  • Loading branch information
lukpueh committed May 24, 2023
1 parent a78288e commit cb09097
Show file tree
Hide file tree
Showing 11 changed files with 13 additions and 1,010 deletions.
23 changes: 0 additions & 23 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,29 +181,6 @@ cryptographic operations.
>>> signature = create_signature(ecdsa_key, data)


Verify ECDSA, Ed25519, and RSA Signatures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

::

# Continuing from the previous sections . . .

>>> data = b'The quick brown fox jumps over the lazy dog'
>>> ed25519_key = generate_ed25519_key()
>>> signature = create_signature(ed25519_key, data)
>>> verify_signature(ed25519_key, signature, data)
True
>>> verify_signature(ed25519_key, signature, 'bad_data')
False
>>> rsa_key = generate_rsa_key()
>>> signature = create_signature(rsa_key, data)
>>> verify_signature(rsa_key, signature, data)
True
>>> ecdsa_key = generate_ecdsa_key()
>>> signature = create_signature(ecdsa_key, data)
>>> verify_signature(ecdsa_key, signature, data)
True


Miscellaneous functions
~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
90 changes: 3 additions & 87 deletions securesystemslib/ecdsa_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
'securesystemslib.ecdsa_keys.py' calls the 'cryptography' library to perform
all of the ecdsa-related operations.
The ecdsa-related functions included here are generate(), create_signature()
and verify_signature(). The 'cryptography' library is used by ecdsa_keys.py
The ecdsa-related functions included here are generate() and create_signature().
The 'cryptography' library is used by ecdsa_keys.py
to perform the actual ECDSA computations, and the functions listed above can
be viewed as an easy-to-use public interface.
"""
Expand All @@ -34,13 +34,12 @@
CRYPTO = True
NO_CRYPTO_MSG = "ECDSA key support requires the cryptography library"
try:
from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.serialization import (
load_pem_private_key,
load_pem_public_key,
)

_SCHEME_HASHER = {
Expand Down Expand Up @@ -260,89 +259,6 @@ def create_signature(
return signature, scheme


def verify_signature(public_key, scheme, signature, data):
"""
<Purpose>
Verify that 'signature' was produced by the private key associated with
'public_key'.
>>> scheme = 'ecdsa-sha2-nistp256'
>>> public, private = generate_public_and_private(scheme)
>>> data = b'The quick brown fox jumps over the lazy dog'
>>> signature, scheme = create_signature(public, private, data, scheme)
>>> verify_signature(public, scheme, signature, data)
True
>>> verify_signature(public, scheme, signature, b'bad data')
False
<Arguments>
public_key:
The ECDSA public key in PEM format. The public key is needed to verify
'signature'.
scheme:
The signature scheme used to generate 'signature'. For example:
'ecdsa-sha2-nistp256'.
signature:
The signature to be verified, which should have been generated by
the private key associated with 'public_key'. 'data'.
data:
Byte data that was used by create_signature() to generate 'signature'.
<Exceptions>
securesystemslib.exceptions.FormatError, if any of the arguments are
improperly formatted.
securesystemslib.exceptions.UnsupportedAlgorithmError, if 'scheme' is
not one of the supported signature schemes.
securesystemslib.exceptions.UnsupportedLibraryError, if the cryptography
module is not available.
<Side Effects>
None.
<Returns>
Boolean, indicating whether the 'signature' of data was generated by
the private key associated with 'public_key'.
"""

if not CRYPTO: # pragma: no cover
raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

# Are the arguments properly formatted?
# If not, raise 'securesystemslib.exceptions.FormatError'.
formats.PEMECDSA_SCHEMA.check_match(public_key)
formats.ECDSA_SCHEME_SCHEMA.check_match(scheme)
formats.ECDSASIGNATURE_SCHEMA.check_match(signature)

try:
ecdsa_key = load_pem_public_key(
public_key.encode("utf-8"), backend=default_backend()
)
except ValueError as e:
raise exceptions.FormatError(
f"Failed to load PEM key {public_key}"
) from e

if not isinstance(ecdsa_key, ec.EllipticCurvePublicKey):
raise exceptions.FormatError(
"Invalid ECDSA public" " key: " + repr(public_key)
)
logger.debug("Loaded a valid ECDSA public key.")

# verify() raises an 'InvalidSignature' exception if 'signature'
# is invalid.
try:
ecdsa_key.verify(signature, data, _SCHEME_HASHER[scheme])
return True

except (TypeError, InvalidSignature):
return False


def create_ecdsa_public_and_private_from_pem(pem, password=None):
"""
<Purpose>
Expand Down
117 changes: 3 additions & 114 deletions securesystemslib/ed25519_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
http://nacl.cr.yp.to/
https://github.com/pyca/ed25519
The ed25519-related functions included here are generate(), create_signature()
and verify_signature(). The 'ed25519' and PyNaCl (i.e., 'nacl') modules used
The ed25519-related functions included here are generate() and create_signature().
The 'ed25519' and PyNaCl (i.e., 'nacl') modules used
by ed25519_keys.py perform the actual ed25519 computations and the functions
listed above can be viewed as an easy-to-use public interface.
"""
Expand Down Expand Up @@ -67,18 +67,13 @@
# avoid conflicts with own exceptions of same name
from nacl import exceptions as nacl_exceptions
from nacl.encoding import RawEncoder
from nacl.signing import SigningKey, VerifyKey
from nacl.signing import SigningKey
except ImportError:
NACL = False

# pylint: disable=wrong-import-position
from securesystemslib import exceptions, formats

# The optimized pure Python implementation of Ed25519. If
# PyNaCl cannot be imported and an attempt to use is made in this module, a
# 'securesystemslib.exceptions.UnsupportedLibraryError' exception is raised.
from securesystemslib._vendor.ed25519 import ed25519 as python_ed25519

# pylint: enable=wrong-import-position

# Supported ed25519 signing schemes: 'ed25519'. The pure Python implementation
Expand Down Expand Up @@ -248,112 +243,6 @@ def create_signature(public_key, private_key, data, scheme):
return signature, scheme


def verify_signature(public_key, scheme, signature, data):
"""
<Purpose>
Determine whether the private key corresponding to 'public_key' produced
'signature'. verify_signature() will use the public key, the 'scheme' and
'sig', and 'data' arguments to complete the verification.
>>> public, private = generate_public_and_private()
>>> data = b'The quick brown fox jumps over the lazy dog'
>>> scheme = 'ed25519'
>>> signature, scheme = \
create_signature(public, private, data, scheme)
>>> verify_signature(public, scheme, signature, data)
True
>>> bad_data = b'The sly brown fox jumps over the lazy dog'
>>> bad_signature, scheme = \
create_signature(public, private, bad_data, scheme)
>>> verify_signature(public, scheme, bad_signature, data)
False
<Arguments>
public_key:
The public key is a 32-byte string.
scheme:
'ed25519' signature scheme used by either the pure python
implementation (i.e., ed25519.py) or PyNacl (i.e., 'nacl').
signature:
The signature is a 64-byte string.
data:
Data object used by securesystemslib.ed25519_keys.create_signature() to
generate 'signature'. 'data' is needed here to verify the signature.
<Exceptions>
securesystemslib.exceptions.UnsupportedAlgorithmError. Raised if the
signature scheme 'scheme' is not one supported by
securesystemslib.ed25519_keys.create_signature().
securesystemslib.exceptions.FormatError. Raised if the arguments are
improperly formatted.
<Side Effects>
nacl.signing.VerifyKey.verify() called if available, otherwise
securesystemslib._vendor.ed25519.ed25519.checkvalid() called to do the
verification.
<Returns>
Boolean. True if the signature is valid, False otherwise.
"""

# Does 'public_key' have the correct format?
# This check will ensure 'public_key' conforms to
# 'securesystemslib.formats.ED25519PUBLIC_SCHEMA', which must have length 32
# bytes. Raise 'securesystemslib.exceptions.FormatError' if the check fails.
formats.ED25519PUBLIC_SCHEMA.check_match(public_key)

# Is 'scheme' properly formatted?
formats.ED25519_SIG_SCHEMA.check_match(scheme)

# Is 'signature' properly formatted?
formats.ED25519SIGNATURE_SCHEMA.check_match(signature)

# Verify 'signature'. Before returning the Boolean result, ensure 'ed25519'
# was used as the signature scheme.
public = public_key
valid_signature = False

if scheme in _SUPPORTED_ED25519_SIGNING_SCHEMES:
if NACL:
try:
nacl_verify_key = VerifyKey(public)
nacl_verify_key.verify(data, signature)
valid_signature = True

except nacl_exceptions.BadSignatureError:
pass

# Verify 'ed25519' signature with the pure Python implementation.
else:
try:
python_ed25519.checkvalid(signature, data, public)
valid_signature = True

# The pure Python implementation raises 'Exception' if 'signature' is
# invalid.
except Exception: # pylint: disable=broad-except # nosec
pass

# This is a defensive check for a valid 'scheme', which should have already
# been validated in the ED25519_SIG_SCHEMA.check_match(scheme) above.
else: # pragma: no cover
message = (
"Unsupported ed25519 signature scheme: "
+ repr(scheme)
+ ".\n"
+ "Supported schemes: "
+ repr(_SUPPORTED_ED25519_SIGNING_SCHEMES)
+ "."
)
raise exceptions.UnsupportedAlgorithmError(message)

return valid_signature


if __name__ == "__main__":
# The interactive sessions of the documentation strings can
# be tested by running 'ed25519_keys.py' as a standalone module.
Expand Down
Loading

0 comments on commit cb09097

Please sign in to comment.