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

Changes to signing build system #166

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
96 changes: 88 additions & 8 deletions ncs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,30 @@ config SUIT_ENVELOPE_TARGET_ENCRYPT

if SUIT_ENVELOPE_TARGET_ENCRYPT

config SUIT_ENVELOPE_TARGET_ENCRYPT_STRING_KEY_ID
string "The string key ID used to identify the encryption key on the device"
default "FWENC_APPLICATION_GEN1" if SOC_NRF54H20_CPUAPP_COMMON
default "FWENC_RADIOCORE_GEN1" if SOC_NRF54H20_CPURAD_COMMON
help
This string is translated to the numeric KEY ID by the encryption script
choice SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN
prompt "SUIT envelope encryption key generation"
default SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN1

config SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN1
bool "Key generation 1"

config SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN2
bool "Key generation 2"
endchoice

config SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_ID
hex "The key ID used to identify the encryption key on the device"
default 0x40022000 if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN1
default 0x40022001 if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN2
default 0x40032000 if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN1
default 0x40032001 if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN2

config SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_NAME
string "Name of the key used for encryption - to identify the key in the KMS"
default SUIT_ENVELOPE_TARGET_ENCRYPT_STRING_KEY_ID
default "FWENC_APPLICATION_GEN1" if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN1
default "FWENC_APPLICATION_GEN2" if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN2
default "FWENC_RADIOCORE_GEN1" if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN1
default "FWENC_RADIOCORE_GEN2" if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_ENCRYPT_KEY_GEN2

choice SUIT_ENVELOPE_TARGET_ENCRYPT_PLAINTEXT_HASH_ALG
prompt "Algorithm used to calculate the digest of the plaintext firmware"
Expand Down Expand Up @@ -105,4 +119,70 @@ config SUIT_ENVELOPE_TARGET_ENCRYPT_PLAINTEXT_HASH_ALG_NAME
default "shake128" if SUIT_ENVELOPE_TARGET_ENCRYPT_PLAINTEXT_HASH_ALG_SHAKE128
default "shake256" if SUIT_ENVELOPE_TARGET_ENCRYPT_PLAINTEXT_HASH_ALG_SHAKE256

endif # SUIT_ENVELOPE_TARGET_ENCRYPT
endif # SUIT_ENVELOPE_TARGET_ENCRYPT

config SUIT_ENVELOPE_TARGET_SIGN
bool "Sign the target envelope"

if SUIT_ENVELOPE_TARGET_SIGN

choice SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN
prompt "SUIT envelope signing key generation"
default SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN1

config SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN1
bool "Key generation 1"

config SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN2
bool "Key generation 2"

config SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN3
bool "Key generation 3"
endchoice

config SUIT_ENVELOPE_TARGET_SIGN_KEY_ID
hex "The key ID used to identify the public key on the device"
default 0x40022100 if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN1
default 0x40022101 if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN2
default 0x40022102 if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN3
default 0x40032100 if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN1
default 0x40032101 if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN2
default 0x40032102 if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN3
help
This string is translated to the numeric KEY ID by the encryption script

config SUIT_ENVELOPE_TARGET_SIGN_PRIVATE_KEY_NAME
string "Name of the private key used for signing - to identify the key in the KMS"
default "MANIFEST_APPLICATION_GEN1_priv" if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN1
default "MANIFEST_APPLICATION_GEN2_priv" if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN2
default "MANIFEST_APPLICATION_GEN3_priv" if SOC_NRF54H20_CPUAPP_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN3
default "MANIFEST_RADIOCORE_GEN1_priv" if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN1
default "MANIFEST_RADIOCORE_GEN2_priv" if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN2
default "MANIFEST_RADIOCORE_GEN3_priv" if SOC_NRF54H20_CPURAD_COMMON && SUIT_ENVELOPE_TARGET_SIGN_KEY_GEN3

choice SUIT_ENVELOPE_TARGET_SIGN_ALG
prompt "Algorithm used to sign the target envelope"
default SUIT_ENVELOPE_TARGET_SIGN_ALG_EDDSA

config SUIT_ENVELOPE_TARGET_SIGN_ALG_EDDSA
bool "Use the EdDSA algorithm"

config SUIT_ENVELOPE_TARGET_SIGN_ALG_ECDSA_256
bool "Use the ECDSA algorithm with key length of 256 bits"

config SUIT_ENVELOPE_TARGET_SIGN_ALG_ECDSA_384
bool "Use the ECDSA algorithm with key length of 384 bits"

config SUIT_ENVELOPE_TARGET_SIGN_ALG_ECDSA_521
bool "Use the ECDSA algorithm with key length of 521 bits"

endchoice

config SUIT_ENVELOPE_TARGET_SIGN_ALG_NAME
string "String name of the algorithm used to sign the target envelope"
default "eddsa" if SUIT_ENVELOPE_TARGET_SIGN_ALG_EDDSA
default "es-256" if SUIT_ENVELOPE_TARGET_SIGN_ALG_ECDSA_256
default "es-384" if SUIT_ENVELOPE_TARGET_SIGN_ALG_ECDSA_384
default "es-521" if SUIT_ENVELOPE_TARGET_SIGN_ALG_ECDSA_521

endif # SUIT_ENVELOPE_TARGET_SIGN
78 changes: 78 additions & 0 deletions ncs/basic_kms.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@

from pathlib import Path
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

from cryptography.hazmat.primitives.serialization import load_pem_private_key, load_der_private_key
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PrivateKey
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature
import math

from suit_generator.suit_kms_base import SuitKMSBase
import json

Expand Down Expand Up @@ -72,6 +82,74 @@ def encrypt(self, plaintext, key_name, context, aad) -> tuple[bytes, bytes, byte

return nonce, tag, ciphertext

def _verify_signing_key_type(self, private_key, algorithm) -> bool:
"""Verify if the key type matches the provided key."""
if isinstance(private_key, EllipticCurvePrivateKey):
return f"es-{private_key.key_size}" == algorithm
elif isinstance(private_key, Ed25519PrivateKey) or isinstance(private_key, Ed448PrivateKey):
return "eddsa" == algorithm
else:
raise ValueError(f"Key {type(private_key)} not supported")

def _create_cose_es_signature(self, input_data, private_key) -> bytes:
"""Create ECDSA signature and return signature bytes."""
hash_map = {256: hashes.SHA256(), 384: hashes.SHA384(), 521: hashes.SHA512()}
dss_signature = private_key.sign(input_data, ec.ECDSA(hash_map[private_key.key_size]))
r, s = decode_dss_signature(dss_signature)
return r.to_bytes(math.ceil(private_key.key_size / 8), byteorder="big") + s.to_bytes(
math.ceil(private_key.key_size / 8), byteorder="big"
)

def _create_cose_ed_signature(self, input_data, private_key) -> bytes:
"""Create ECDSA signature and return signature bytes."""
return private_key.sign(input_data)

def _get_sign_method(self, private_key) -> bool:
"""Return sign method based on key type."""
if isinstance(private_key, EllipticCurvePrivateKey):
return self._create_cose_es_signature
elif isinstance(private_key, Ed25519PrivateKey) or isinstance(private_key, Ed448PrivateKey):
return self._create_cose_ed_signature
else:
raise ValueError(f"Key {type(private_key)} not supported")

def sign(self, data, key_name, algorithm, context) -> bytes:
"""
Sign the data with a private key.

:param data: The data to be signed.
:param key_name: The name of the private key to be used.
:param algorithm: The name of the algorithm to be used.
Used to verify if the key in the provided file contains a key of a compatible type.
:param context: The context to be used

:return: The signature.
:rtype: bytes
"""
key_file_name = key_name + ".pem"

private_key_path = self.keys_directory / key_file_name

if Path(key_name + ".pem").is_file():
key_file_name = key_name + ".pem"
loader = load_pem_private_key
elif Path(key_name + ".der").is_file():
key_file_name = key_name + ".der"
loader = load_der_private_key
else:
raise ValueError(f"Key file {key_name} not found - neither {key_name}.pem nor {key_name}.der exists")

with open(private_key_path, "rb") as private_key:
private_key = loader(private_key.read(), None)

if not self._verify_signing_key_type(private_key, algorithm):
raise ValueError(f"Key {key_file_name} is not compatible with algorithm {algorithm}")

sign_method = self._get_sign_method(private_key)
signature = sign_method(data, private_key)

return signature


def suit_kms_factory():
"""Get a KMS object."""
Expand Down
Loading
Loading