Skip to content

Commit

Permalink
New version of signing script and signing process
Browse files Browse the repository at this point in the history
Ref: NCSDK-31069

Signed-off-by: Artur Hadasz <[email protected]>
  • Loading branch information
ahasztag committed Jan 16, 2025
1 parent 7cde03f commit 6fcaebb
Show file tree
Hide file tree
Showing 11 changed files with 736 additions and 257 deletions.
68 changes: 67 additions & 1 deletion ncs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,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
77 changes: 77 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,73 @@ 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) -> 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) -> 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
"""
# TODO: support DER format
key_file_name = key_name + ".pem"
private_key_path = self.keys_directory / key_file_name
loaders = {
".pem": load_pem_private_key,
".der": load_der_private_key,
}

try:
loader = loaders[private_key_path.suffix]
except KeyError as e:
raise ValueError("Unrecognized private key format. Extension must be {per,der}") from e
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
2 changes: 2 additions & 0 deletions ncs/encrypt_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ def init_kms_backend(self, kms_script, context):
"""Initialize the KMS from the provided script backend based on the passed context."""
module_name = "SuitKMS_module"
kms_module = _import_module_from_path(module_name, kms_script)
if not hasattr(kms_module, "suit_kms_factory"):
raise ValueError(f"Python script {kms_script} does not contain the required suit_kms_factory function")
self.kms = kms_module.suit_kms_factory()
if not isinstance(self.kms, SuitKMSBase):
raise ValueError(f"Class {type(self.kms)} does not implement the required SuitKMSBase interface")
Expand Down
20 changes: 20 additions & 0 deletions ncs/sample_recursive_sign_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"key-name": "MANIFEST_OEM_ROOT_GEN1_priv",
"key-id": "0x4000AA00",
"alg": "eddsa",
"context": "<CONTEXT (by default path to key directory)>",
"sign-script": "<SIGN_SCRIPT path>",
"kms-script": "<KMS_SCRIPT path>",
"omit-signing": false,
"already-signed-action": "error",
"dependencies" : {
"#radio" : {
"key-name": "MANIFEST_RADIOCORE_GEN1_priv",
"key-id": "0x40032100"
},
"#application" : {
"key-name": "MANIFEST_APPLICATION_GEN1_priv",
"key-id": "0x40022100"
}
}
}
Loading

0 comments on commit 6fcaebb

Please sign in to comment.