Skip to content

Commit

Permalink
Merge pull request secure-systems-lab#763 from lukpueh/fix-ec-default
Browse files Browse the repository at this point in the history
SSlibKey: fix ecdsa nistp384 default scheme
  • Loading branch information
lukpueh authored Apr 12, 2024
2 parents fdaa97b + ef09ef3 commit 73bba08
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 36 deletions.
67 changes: 33 additions & 34 deletions securesystemslib/signer/_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric.ec import (
ECDSA,
SECP256R1,
SECP384R1,
EllipticCurvePublicKey,
)
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Expand Down Expand Up @@ -245,32 +247,39 @@ def _crypto_key(self) -> "PublicKeyTypes":
return load_pem_public_key(public_bytes)

@staticmethod
def _get_keytype_for_crypto_key(public_key: "PublicKeyTypes") -> str:
"""Helper to return keytype for pyca/cryptography public key."""
if isinstance(public_key, RSAPublicKey):
return "rsa"
def _from_crypto(public_key: "PublicKeyTypes") -> Tuple[str, str, str]:
"""Return tuple of keytype, default scheme and serialized public key
value for the passed public key.
if isinstance(public_key, EllipticCurvePublicKey):
return "ecdsa"
Raise ValueError if public key is not supported.
"""

if isinstance(public_key, Ed25519PublicKey):
return "ed25519"
def _raw() -> str:
return public_key.public_bytes(
encoding=Encoding.Raw, format=PublicFormat.Raw
).hex()

raise ValueError(f"unsupported 'public_key' type {type(public_key)}")
def _pem() -> str:
return public_key.public_bytes(
encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo
).decode()

@staticmethod
def _get_default_scheme(keytype: str) -> str:
"""Helper to return default scheme for keytype."""
if keytype == "rsa":
return "rsassa-pss-sha256"
if isinstance(public_key, RSAPublicKey):
return "rsa", "rsassa-pss-sha256", _pem()

if keytype == "ecdsa":
return "ecdsa-sha2-nistp256"
if isinstance(public_key, EllipticCurvePublicKey):
if isinstance(public_key.curve, SECP256R1):
return "ecdsa", "ecdsa-sha2-nistp256", _pem()

if keytype == "ed25519":
return "ed25519"
if isinstance(public_key.curve, SECP384R1):
return "ecdsa", "ecdsa-sha2-nistp384", _pem()

raise ValueError(f"unsupported 'keytype' {keytype}")
raise ValueError(f"unsupported curve '{public_key.curve.name}'")

if isinstance(public_key, Ed25519PublicKey):
return "ed25519", "ed25519", _raw()

raise ValueError(f"unsupported key '{type(public_key)}'")

@classmethod
def from_crypto(
Expand All @@ -285,7 +294,8 @@ def from_crypto(
public_key: pyca/cryptography public key object.
keyid: Key identifier. If not passed, a default keyid is computed.
scheme: SSlibKey signing scheme. Defaults are "rsassa-pss-sha256",
"ecdsa-sha2-nistp256", and "ed25519" according to the keytype
"ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384" and "ed25519"
according to the keytype.
Raises:
UnsupportedLibraryError: pyca/cryptography not installed
Expand All @@ -298,21 +308,10 @@ def from_crypto(
if CRYPTO_IMPORT_ERROR:
raise UnsupportedLibraryError(CRYPTO_IMPORT_ERROR)

keytype = cls._get_keytype_for_crypto_key(public_key)
if not scheme:
scheme = cls._get_default_scheme(keytype)

if keytype in ["rsa", "ecdsa"]:
pem: bytes = public_key.public_bytes(
encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo
)
public_key_value = pem.decode()
keytype, default_scheme, public_key_value = cls._from_crypto(public_key)

else: # ed25519
raw: bytes = public_key.public_bytes(
encoding=Encoding.Raw, format=PublicFormat.Raw
)
public_key_value = raw.hex()
if not scheme:
scheme = default_scheme

keyval = {"public": public_key_value}

Expand Down
6 changes: 6 additions & 0 deletions tests/data/pems/ecdsa_secp384r1_private.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCcHGK5kIyeNu1WvNqh
02kwOdu5BFuYptulHFJRWiaIXrC9nwgtWDjNco8BTIKYdTmhZANiAASSwAbzSctS
Sw4NMRQFM8kk9g3Rt/GGSuvaGXKiR9EbiQNixFE3zq9bDENNbuqFY1k8WEkwnEea
8ewJsvP8gXuF2jxe/+9E7gxUdvCrR+JbOdS+RmjAcLl8fYQS80XVHm0=
-----END PRIVATE KEY-----
5 changes: 5 additions & 0 deletions tests/data/pems/ecdsa_secp384r1_public.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEksAG80nLUksODTEUBTPJJPYN0bfxhkrr
2hlyokfRG4kDYsRRN86vWwxDTW7qhWNZPFhJMJxHmvHsCbLz/IF7hdo8Xv/vRO4M
VHbwq0fiWznUvkZowHC5fH2EEvNF1R5t
-----END PUBLIC KEY-----
13 changes: 11 additions & 2 deletions tests/test_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,16 +299,25 @@ def test_from_crypto(self):
"rsa",
"rsassa-pss-sha256",
"2f685fa7546f1856b123223ab086b3def14c89d24eef18f49c32508c2f60e241",
"rsa_public.pem",
),
(
"ecdsa",
"ecdsa-sha2-nistp256",
"50d7e110ad65f3b2dba5c3cfc8c5ca259be9774cc26be3410044ffd4be3aa5f3",
"ecdsa_public.pem",
),
(
"ecdsa",
"ecdsa-sha2-nistp384",
"0155661bdf705f621a74f55eef36c9ae041e456141eced7a45d4a1f75ded9ac0",
"ecdsa_secp384r1_public.pem",
),
(
"ed25519",
"ed25519",
"c6d8bf2e4f48b41ac2ce8eca21415ca8ef68c133b47fc33df03d4070a7e1e9cc",
"ed25519_public.pem",
),
]

Expand All @@ -319,8 +328,8 @@ def _from_file(path):
crypto_key = load_pem_public_key(pem)
return crypto_key

for keytype, default_scheme, default_keyid in test_data:
crypto_key = _from_file(PEMS_DIR / f"{keytype}_public.pem")
for keytype, default_scheme, default_keyid, fname in test_data:
crypto_key = _from_file(PEMS_DIR / fname)
key = SSlibKey.from_crypto(crypto_key)
self.assertEqual(key.keytype, keytype)
self.assertEqual(key.scheme, default_scheme)
Expand Down

0 comments on commit 73bba08

Please sign in to comment.