Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vendoring-compatible imports #316

Merged
merged 18 commits into from
Feb 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions securesystemslib/ecdsa_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
from cryptography.hazmat.primitives.serialization import load_pem_public_key
from cryptography.hazmat.primitives.serialization import load_pem_private_key

import cryptography.exceptions
from cryptography.exceptions import (InvalidSignature, UnsupportedAlgorithm)

_SCHEME_HASHER = {
'ecdsa-sha2-nistp256': ec.ECDSA(hashes.SHA256()),
Expand All @@ -62,8 +62,8 @@
CRYPTO = False

# Perform object format-checking and add ability to handle/raise exceptions.
import securesystemslib.formats
import securesystemslib.exceptions
from securesystemslib import exceptions
from securesystemslib import formats

_SUPPORTED_ECDSA_SCHEMES = ['ecdsa-sha2-nistp256']

Expand Down Expand Up @@ -131,14 +131,14 @@ def generate_public_and_private(scheme='ecdsa-sha2-nistp256'):
"""

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

# Does 'scheme' have the correct format?
# Verify that 'scheme' is of the correct type, and that it's one of the
# supported ECDSA . It must conform to
# 'securesystemslib.formats.ECDSA_SCHEME_SCHEMA'. Raise
# 'securesystemslib.exceptions.FormatError' if the check fails.
securesystemslib.formats.ECDSA_SCHEME_SCHEMA.check_match(scheme)
formats.ECDSA_SCHEME_SCHEMA.check_match(scheme)

public_key = None
private_key = None
Expand All @@ -153,7 +153,7 @@ def generate_public_and_private(scheme='ecdsa-sha2-nistp256'):
# The ECDSA_SCHEME_SCHEMA.check_match() above should have detected any
# invalid 'scheme'. This is a defensive check.
else: #pragma: no cover
raise securesystemslib.exceptions.UnsupportedAlgorithmError('An unsupported'
raise exceptions.UnsupportedAlgorithmError('An unsupported'
' scheme specified: ' + repr(scheme) + '.\n Supported'
' algorithms: ' + repr(_SUPPORTED_ECDSA_SCHEMES))

Expand Down Expand Up @@ -220,19 +220,19 @@ def create_signature(public_key, private_key, data, scheme='ecdsa-sha2-nistp256'
"""

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

# Do 'public_key' and 'private_key' have the correct format?
# This check will ensure that the arguments conform to
# 'securesystemslib.formats.PEMECDSA_SCHEMA'. Raise
# 'securesystemslib.exceptions.FormatError' if the check fails.
securesystemslib.formats.PEMECDSA_SCHEMA.check_match(public_key)
formats.PEMECDSA_SCHEMA.check_match(public_key)

# Is 'private_key' properly formatted?
securesystemslib.formats.PEMECDSA_SCHEMA.check_match(private_key)
formats.PEMECDSA_SCHEMA.check_match(private_key)

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

# 'ecdsa-sha2-nistp256' is the only currently supported ECDSA scheme, so this
# if-clause isn't strictly needed. Nevertheless, the conditional statement
Expand All @@ -246,13 +246,13 @@ def create_signature(public_key, private_key, data, scheme='ecdsa-sha2-nistp256'
signature = private_key.sign(data, ec.ECDSA(hashes.SHA256()))

except TypeError as e:
raise securesystemslib.exceptions.CryptoError('Could not create'
raise exceptions.CryptoError('Could not create'
' signature: ' + str(e))

# A defensive check for an invalid 'scheme'. The
# ECDSA_SCHEME_SCHEMA.check_match() above should have already validated it.
else: #pragma: no cover
raise securesystemslib.exceptions.UnsupportedAlgorithmError('Unsupported'
raise exceptions.UnsupportedAlgorithmError('Unsupported'
' signature scheme is specified: ' + repr(scheme))

return signature, scheme
Expand Down Expand Up @@ -311,19 +311,19 @@ def verify_signature(public_key, scheme, signature, data):
"""

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

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

ecdsa_key = load_pem_public_key(public_key.encode('utf-8'),
backend=default_backend())

if not isinstance(ecdsa_key, ec.EllipticCurvePublicKey):
raise securesystemslib.exceptions.FormatError('Invalid ECDSA public'
raise exceptions.FormatError('Invalid ECDSA public'
' key: ' + repr(public_key))

else:
Expand All @@ -335,7 +335,7 @@ def verify_signature(public_key, scheme, signature, data):
ecdsa_key.verify(signature, data, _SCHEME_HASHER[scheme])
return True

except (TypeError, cryptography.exceptions.InvalidSignature):
except (TypeError, InvalidSignature):
return False


Expand Down Expand Up @@ -394,15 +394,15 @@ def create_ecdsa_public_and_private_from_pem(pem, password=None):
"""

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

# Does 'pem' have the correct format?
# This check will ensure 'pem' conforms to
# 'securesystemslib.formats.ECDSARSA_SCHEMA'.
securesystemslib.formats.PEMECDSA_SCHEMA.check_match(pem)
formats.PEMECDSA_SCHEMA.check_match(pem)

if password is not None:
securesystemslib.formats.PASSWORD_SCHEMA.check_match(password)
formats.PASSWORD_SCHEMA.check_match(password)
password = password.encode('utf-8')

else:
Expand All @@ -418,8 +418,8 @@ def create_ecdsa_public_and_private_from_pem(pem, password=None):
private = load_pem_private_key(pem.encode('utf-8'), password=password,
backend=default_backend())

except (ValueError, cryptography.exceptions.UnsupportedAlgorithm) as e:
raise securesystemslib.exceptions.CryptoError('Could not import private'
except (ValueError, UnsupportedAlgorithm) as e:
raise exceptions.CryptoError('Could not import private'
' PEM.\n' + str(e))

public = private.public_key()
Expand Down Expand Up @@ -481,14 +481,14 @@ def create_ecdsa_encrypted_pem(private_pem, passphrase):
"""

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

# Does 'private_key' have the correct format?
# Raise 'securesystemslib.exceptions.FormatError' if the check fails.
securesystemslib.formats.PEMRSA_SCHEMA.check_match(private_pem)
formats.PEMRSA_SCHEMA.check_match(private_pem)

# Does 'passphrase' have the correct format?
securesystemslib.formats.PASSWORD_SCHEMA.check_match(passphrase)
formats.PASSWORD_SCHEMA.check_match(passphrase)

private = load_pem_private_key(private_pem.encode('utf-8'), password=None,
backend=default_backend())
Expand Down
49 changes: 25 additions & 24 deletions securesystemslib/ed25519_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,20 @@
NACL = True
NO_NACL_MSG = "ed25519 key support requires the nacl library"
try:
import nacl.signing
import nacl.encoding
from nacl.encoding import RawEncoder
from nacl.signing import (SigningKey, VerifyKey)
# avoid conflicts with own exceptions of same name
from nacl import exceptions as nacl_exceptions
except ImportError:
NACL = False

# 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.
import securesystemslib._vendor.ed25519.ed25519
from securesystemslib._vendor.ed25519 import ed25519 as python_ed25519

import securesystemslib.formats
import securesystemslib.exceptions
from securesystemslib import exceptions
from securesystemslib import formats

# Supported ed25519 signing schemes: 'ed25519'. The pure Python implementation
# (i.e., ed25519') and PyNaCl (i.e., 'nacl', libsodium + Python bindings)
Expand Down Expand Up @@ -130,7 +132,7 @@ def generate_public_and_private():
"""

if not NACL: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_NACL_MSG)
raise exceptions.UnsupportedLibraryError(NO_NACL_MSG)

# Generate ed25519's seed key by calling os.urandom(). The random bytes
# returned should be suitable for cryptographic use and is OS-specific.
Expand All @@ -142,8 +144,8 @@ def generate_public_and_private():

# Generate the public key. PyNaCl (i.e., 'nacl' module) performs the actual
# key generation.
nacl_key = nacl.signing.SigningKey(seed)
public = nacl_key.verify_key.encode(encoder=nacl.encoding.RawEncoder())
nacl_key = SigningKey(seed)
public = nacl_key.verify_key.encode(encoder=RawEncoder())

return public, seed

Expand Down Expand Up @@ -210,19 +212,19 @@ def create_signature(public_key, private_key, data, scheme):
"""

if not NACL: # pragma: no cover
raise securesystemslib.exceptions.UnsupportedLibraryError(NO_NACL_MSG)
raise exceptions.UnsupportedLibraryError(NO_NACL_MSG)

# 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.
securesystemslib.formats.ED25519PUBLIC_SCHEMA.check_match(public_key)
formats.ED25519PUBLIC_SCHEMA.check_match(public_key)

# Is 'private_key' properly formatted?
securesystemslib.formats.ED25519SEED_SCHEMA.check_match(private_key)
formats.ED25519SEED_SCHEMA.check_match(private_key)

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

# Signing the 'data' object requires a seed and public key.
# nacl.signing.SigningKey.sign() generates the signature.
Expand All @@ -233,18 +235,18 @@ def create_signature(public_key, private_key, data, scheme):
# statement to accommodate schemes that might be added in the future.
if scheme == 'ed25519':
try:
nacl_key = nacl.signing.SigningKey(private_key)
nacl_key = SigningKey(private_key)
nacl_sig = nacl_key.sign(data)
signature = nacl_sig.signature

except (ValueError, TypeError, nacl.exceptions.CryptoError) as e:
raise securesystemslib.exceptions.CryptoError('An "ed25519" signature'
except (ValueError, TypeError, nacl_exceptions.CryptoError) as e:
raise exceptions.CryptoError('An "ed25519" signature'
' could not be created with PyNaCl.' + str(e))

# This is a defensive check for a valid 'scheme', which should have already
# been validated in the check_match() above.
else: #pragma: no cover
raise securesystemslib.exceptions.UnsupportedAlgorithmError('Unsupported'
raise exceptions.UnsupportedAlgorithmError('Unsupported'
' signature scheme is specified: ' + repr(scheme))

return signature, scheme
Expand Down Expand Up @@ -309,13 +311,13 @@ def verify_signature(public_key, scheme, signature, data):
# 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.
securesystemslib.formats.ED25519PUBLIC_SCHEMA.check_match(public_key)
formats.ED25519PUBLIC_SCHEMA.check_match(public_key)

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

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

# Verify 'signature'. Before returning the Boolean result, ensure 'ed25519'
# was used as the signature scheme.
Expand All @@ -325,18 +327,17 @@ def verify_signature(public_key, scheme, signature, data):
if scheme in _SUPPORTED_ED25519_SIGNING_SCHEMES:
if NACL:
try:
nacl_verify_key = nacl.signing.VerifyKey(public)
nacl_verify_key = VerifyKey(public)
nacl_verify_key.verify(data, signature)
valid_signature = True

except nacl.exceptions.BadSignatureError:
except nacl_exceptions.BadSignatureError:
pass

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

# The pure Python implementation raises 'Exception' if 'signature' is
Expand All @@ -349,7 +350,7 @@ def verify_signature(public_key, scheme, signature, data):
else: #pragma: no cover
message = 'Unsupported ed25519 signature scheme: ' + repr(scheme) + '.\n' + \
'Supported schemes: ' + repr(_SUPPORTED_ED25519_SIGNING_SCHEMES) + '.'
raise securesystemslib.exceptions.UnsupportedAlgorithmError(message)
raise exceptions.UnsupportedAlgorithmError(message)

return valid_signature

Expand Down
18 changes: 9 additions & 9 deletions securesystemslib/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@
import time
import six

import securesystemslib.schema as SCHEMA
import securesystemslib.exceptions
from securesystemslib import exceptions
from securesystemslib import schema as SCHEMA
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you kept as SCHEMA to make the commit less invasive? This might be something to note in the commit message.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you want to reword the commit message. Otherwise, I'll just go ahead and merge. :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes exactly. And I think I can live with that message if you can :)


# Note that in the schema definitions below, the 'SCHEMA.Object' types allow
# additional keys which are not defined. Thus, any additions to them will be
Expand Down Expand Up @@ -476,7 +476,7 @@ def datetime_to_unix_timestamp(datetime_object):
# Raise 'securesystemslib.exceptions.FormatError' if not.
if not isinstance(datetime_object, datetime.datetime):
message = repr(datetime_object) + ' is not a datetime.datetime() object.'
raise securesystemslib.exceptions.FormatError(message)
raise exceptions.FormatError(message)

unix_timestamp = calendar.timegm(datetime_object.timetuple())

Expand Down Expand Up @@ -554,7 +554,7 @@ def format_base64(data):
return binascii.b2a_base64(data).decode('utf-8').rstrip('=\n ')

except (TypeError, binascii.Error) as e:
raise securesystemslib.exceptions.FormatError('Invalid base64'
raise exceptions.FormatError('Invalid base64'
' encoding: ' + str(e))


Expand Down Expand Up @@ -583,7 +583,7 @@ def parse_base64(base64_string):

if not isinstance(base64_string, six.string_types):
message = 'Invalid argument: '+repr(base64_string)
raise securesystemslib.exceptions.FormatError(message)
raise exceptions.FormatError(message)

extra = len(base64_string) % 4
if extra:
Expand All @@ -594,7 +594,7 @@ def parse_base64(base64_string):
return binascii.a2b_base64(base64_string.encode('utf-8'))

except (TypeError, binascii.Error) as e:
raise securesystemslib.exceptions.FormatError('Invalid base64'
raise exceptions.FormatError('Invalid base64'
' encoding: ' + str(e))


Expand Down Expand Up @@ -661,7 +661,7 @@ def _encode_canonical(object, output_function):
_encode_canonical(value, output_function)
output_function("}")
else:
raise securesystemslib.exceptions.FormatError('I cannot encode '+repr(object))
raise exceptions.FormatError('I cannot encode '+repr(object))


def encode_canonical(object, output_function=None):
Expand Down Expand Up @@ -724,9 +724,9 @@ def encode_canonical(object, output_function=None):
try:
_encode_canonical(object, output_function)

except (TypeError, securesystemslib.exceptions.FormatError) as e:
except (TypeError, exceptions.FormatError) as e:
message = 'Could not encode ' + repr(object) + ': ' + str(e)
raise securesystemslib.exceptions.FormatError(message)
raise exceptions.FormatError(message)

# Return the encoded 'object' as a string.
# Note: Implies 'output_function' is None,
Expand Down
Loading