Skip to content

Commit

Permalink
SSlibKey: Fix ec default scheme bug and vet scheme
Browse files Browse the repository at this point in the history
Signed-off-by: Lukas Puehringer <[email protected]>
  • Loading branch information
lukpueh committed Apr 2, 2024
1 parent 185aa9c commit 782e675
Showing 1 changed file with 72 additions and 36 deletions.
108 changes: 72 additions & 36 deletions securesystemslib/signer/_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import logging
from abc import ABCMeta, abstractmethod
from typing import Any, Dict, Optional, Tuple, Type, cast
from typing import Any, Callable, Dict, Optional, Tuple, Type, cast

from securesystemslib._vendor.ed25519.ed25519 import (
SignatureMismatch,
Expand All @@ -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,68 @@ 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, list[str], Callable]:
"""Return tuple of keytype, default scheme, supported schemes list, and
a function to lazy-serialize the public key value using the keytype
-specific format.
if isinstance(public_key, EllipticCurvePublicKey):
return "ecdsa"
raise ValueError if public key is not supported
"""

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

raise ValueError(f"unsupported 'public_key' type {type(public_key)}")
def _pem():
pem: bytes = public_key.public_bytes(
encoding=Encoding.PEM, format=PublicFormat.SubjectPublicKeyInfo
)
return pem.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",
[
"rsassa-pss-sha224",
"rsassa-pss-sha256",
"rsassa-pss-sha384",
"rsassa-pss-sha512",
"rsa-pkcs1v15-sha224",
"rsa-pkcs1v15-sha256",
"rsa-pkcs1v15-sha384",
"rsa-pkcs1v15-sha512",
],
_pem,
)

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

if isinstance(public_key.curve, SECP384R1):
return (
"ecdsa",
"ecdsa-sha2-nistp384",
["ecdsa-sha2-nistp384"],
_pem,
)

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

if keytype == "ed25519":
return "ed25519"
if isinstance(public_key, Ed25519PublicKey):
return "ed25519", "ed25519", ["ed25519"], _raw

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

@classmethod
def from_crypto(
Expand All @@ -285,7 +323,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,23 +337,20 @@ 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, supported_schemes, public_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 scheme:
if scheme not in supported_schemes:
raise ValueError(
f"unsupported '{scheme}' for key {type(public_key)}, "
f"supported schemes are: {supported_schemes}"
)
else:
scheme = default_scheme

keyval = {"public": public_key_value}
keyval = {"public": public_value()}

if not keyid:
keyid = compute_default_keyid(keytype, scheme, keyval)
Expand Down

0 comments on commit 782e675

Please sign in to comment.