Skip to content

Commit

Permalink
Add missing signature provider example
Browse files Browse the repository at this point in the history
  • Loading branch information
marekvi95 committed May 4, 2023
1 parent bae3d35 commit 85b6e0d
Show file tree
Hide file tree
Showing 13 changed files with 466 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/signature_provider/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*
92 changes: 92 additions & 0 deletions examples/signature_provider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Signature Provider Integration

This example demonstrates how to use a custom remote signing service for signing data such as Debug Credential file or Masterboot image.

## 1. Content
This chapter describes the content of this directory

### 1.1 Signature Provider
Content of the `hsm` directory represents the remote side of things

`hsm/sahsm.py` represents a remote signing service

`hsm/sasp.py` is the custom Signature Provider, an interface to the signing service.
It contains a class derived from `spsdk.crypto.SignatureProvider`

- the derived class has to implement:
- `sp_type: str`: class attribute that identifies the concrete implementation of SignatureProvider
- `sign(bytes) -> bytes`: method which performs the actual signing
- `signature_length -> str`: property which returns a length of a signature
- the derived class can also optionally implement:
- `info() -> str`: method which returns information about the signature provider (for debugging purposes). The default implementation returns a class name as a string
- `verify_public_key(bytes) -> bool`: method which verifies if a given public key matches a private key. If not implemented, the `SPSDKUnsupportedOperation` exceptipon is raised.

> Omitting the implementation of optional methods such as `info()` or `verify(bytes)` does not break the functionality of application.
### 1.2 Debug Credentials
Content of the `dat` directory holds the files required for running the example for Debug Credentials application

`dat/dck_rsa_2048.yml`
- configuration file for `nxpdebugmbox gendc` command
- new configuration field `sign_provider`/`signProvider`(both accepted) has been introduced
- new configuration field `rot_id`:
- due to the nature of creating Debug Credential file we need to know in advance which of the private keys will be used to perform the actual signing
- `rot_id` is a 0-based index representing the private key that will be used with respect to `rot_meta`
- e.g.: if we want to use a private key that corresponds to the public key `p1_cert0_2048.pub`, `rot_id` has to be set to `1`

### 1.3 Masterboot Image
Content of the `mbimg` directory holds the files required for running the example for Masterboot Image application

`mbimg/mbimg_rsa_2048.yml`
- configuration file for `nxpimage mbi export` command
- new configuration field `sign_provider`/`signProvider`(both accepted) has been introduced
- the `sign_provider`/`signProvider` and `mainCertPrivateKeyFile` configuration fields are mutually exclusive as they have the same purpose


## 2. How to run this example
### 2.1 Remote signature service

- install two additional dependencies:
- `pip install flask requests`
- run the custom HSM (a flask application) in a separate shell:
- `python hsm\sahsm.py`

### 2.2 Debug Cedentials
The steps required for signing generated debug certificate with remote signing service:

- Check the configuration file
- `dat/dck_rsa_2048.yml` config file is preconfigured to use `sasp` signature provider
- see the [next chapter](#3-signature-provider-config-values) for better understanding of the configuration values
> For comparison, you may try to use signing a local file, to do so, comment out line 115 in `dat/dck_rsa_2048.yml` file and uncomment line 114 or 118 (the have the same effect)
- Generate signed debug certificate
- `nxpdebugmbox gendc --config dat/dck_rsa_2048.yml --plugin hsm/sasp.py my.dc`

> Use `--plugin` parameter in order to integrate custom signature provider
> Use `--force` flag if you run the example multiple times

### 2.2 Masterboot image
The steps required for signing generated masteboot image with remote signing service:

- Check the configuration file
- `mbimg/mbimg_rsa_2048.yml` config file is preconfigured to use `sasp` signature provider
- see the [next chapter](#3-signature-provider-config-values) for better understanding of the configuration values
> For comparison, you may try to use signing a local file, to do so, comment out line 34 in `mbimg/mbimg_rsa_2048.yml` file and uncomment line 32 or 33 (the have the same effect)
- Generate signed masterboot image
- `nxpimage mbi export --plugin hsm/sasp.py mbimg/mbimg_rsa_2048.yml`

> Use `--plugin` parameter in order to integrate custom signature provider

## 3 Signature provider config values
The signature provider configuration must meet following rules:
- Configuration key
- key names `sign_provider` or `signProvider` are allowed

- Configuration value
- format `"type=<sp_type>;<key1>=<value1>;<key2>=<value2>;..."`
- the `sp_type` has to match the sp_type class attribute defined in the custom signature provider(`hsm/sasp.py`)
- the remaining key-value pairs are passed to the `__init__` method of the concrete Signature Provider
- e.g.: `"type=file;file_path=private_key.pem"` will instantiate `spsdk.crypto.PlainFileSP(file_path='private_key.pem')`

8 changes: 8 additions & 0 deletions examples/signature_provider/dat/dck.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA1he46CuxkrKa+P+Nu4t796KAyDJLQDQHRCDK2GoOZPjxpKfBTfZL
cDA94hYyLD3WNKkXauz2rN1YpYxyXuSeSow1IfxW5HtZyIq4aOtlURDie0kR35Gw
H9B0wpmgj/Ms3+8plGbtUHmjs50GSXP5LHU+BzxyCosLG7+YJusYfUcRisalox55
e56F7MFxvA6XVgDWe7Nk2Ydrh0svN7Pzj1lm6yzkxogQ7yyRgLcXdTunzIN0HBta
RZZY05PTX3Li2tCTPeFB0cARr8qS/gtKB7G1kuj2utO5ZBGQ84kE1m45fsbEyOP1
aNpT5y9OpSy3oIJCNfzHi5JiOqWrlpDeyQIDAQAB
-----END RSA PUBLIC KEY-----
119 changes: 119 additions & 0 deletions examples/signature_provider/dat/dck_rsa_2048.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# DC Block structure
# ============================================
# ============================================
# ============================================
# === Version ===
# ============================================
# === Soc Class ===
# ============================================
# === UUID ===
# ============================================
# === RoT Meta SHA256 of following: ===
# === RoT Key0 SHA256 ===
# === RoT Key1 SHA256 ===
# === RoT Key2 SHA256 ===
# === RoT Key3 SHA256 ===
# ============================================
# === Debugger Key DCK (Pub): ===
# === Mod: 2048 Exp: 32 ===
# ============================================
# === CC SOCU ===
# ============================================
# === CC VU ===
# ============================================
# === CB ===
# ============================================
# === RoT Key (pub) ===
# === Mod: 2048 Exp: 32 ===
# ============================================
# ============================================
# === Signature of all block ===
# === SHA256 of whole block => RSA(RoTK) ===
# ============================================
# ============================================
# ============================================

# ============ SoC Class ============
# A unique identifier for a set of SoCs that require no SoC-specific differentiation in
# their debug authentication. The main usage is to allow a different set of debug
# domains and options to be negotiated between the device configuration and
# credentials. A class can contain just a single revision of a single SoC model, if the
# granularity of debug control warrants it.
# Examples list of possible settings:
# 0x0001: LPC550x, LPC55s0x, LPC551x, LPC55s1x, LPC552x, LPC55s2x, LPC55s3x, LPC55s6x

socc: 0x0001

# ============ Device UUID ============
# 128-bit IETF RFC4122 compliant non-sequential Universally Unique Identifier (UUID)
uuid: "E004090E6BDD2155BBCE9E0665805BE3"

# ============ SoC Usage ============
# A CC (constraint) value that is a bit mask, and whose bits are used in an
# SoCC-specific manner. These bits are typically used for controlling which debug
# domains are accessed via the authentication protocol, but device-specific debug
# options can be managed in this way also.
cc_socu: 0x03FF

# ============ Vendor Usage ============
# A CC (constraint) value that is opaque to the debug authentication protocol itself but
# which can be leveraged by vendors in product-specific ways.
cc_vu: 0x5678

# ============ Credential Beacon & Authentication beacon ============
# A value that is passed through the authentication protocol, which is not interpreted
# by the protocol but is instead made visible to the application being debugged. A
# credential beacon is associated with a DC and is therefore vendor/RoT-signed. An
# authentication beacon is provided and signed by the debugger during the
# authentication process.
cc_beacon: 0

# ============ RoT meta-data ============
# The RoT meta-data required by the device to corroborate; the ROTID sent in the
# DAC, the field in this DC, and any additional RoT state that is not stored within the
# device. This allows different RoT identification, management and revocation
# solutions to be handled.
rot_meta:
- ./p0_cert0_2048.pub
- ./p1_cert0_2048.pub

# ============ RoT Identifier ============
# RoTID allows the debugger to infer which RoT public key(s) are acceptable to the
# device. If the debugger cannot or does not provide such a credential, the
# authentication process will fail.
rot_id: 0

# ============ Debug Credential Key ============
# Copyright 2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause

# A user-owned key pair. The public part of the key is associated with a DC, the
# private part is held by the user and used to produce signatures during
# authentication.
dck: ./dck.pub

# ==================================================================================================
# Signature configuration area
# ==================================================================================================
# There are two ways how sign the final DC data blob.
#
# 1. In case that you have available private pair for rot_meta with index rot_id just use first simple style
# to use it by rotk key. As a second way to do same is use sign_provider option with 'type=file'.
#
# 2. For case that Debug Credential files are generated in untrusted environment (without access to RoT private keys),
# there is option to use plugin (example how to create own plugin is in: ./SPSDK/examples/dat/hsm/). The plugin
# has simple interface that allows handle DC data blob into plugin with index of RoT meta public key to get back signed
# DC image.
#
# Those options are exclusive, so only one option could be used to sign the DC.

# ============ Signature Provider ============
# To use signing provider examples
#
# sign_provider: 'type=file;file_path=./../hsm/hsm_k0_cert0_2048.pem'
sign_provider: "type=sasp;key_number=0"
# ============ RoT signature private key ============
# Private key for for the RoT meta chosen by rot_id to sign the image.
# rotk: rotk0.pem

8 changes: 8 additions & 0 deletions examples/signature_provider/dat/p0_cert0_2048.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEApLuDyNSAV8iId3Jb5KE1mKloQ/d2hwxpG6Ek3Kp5EEHCjfQ4PqBY
mSfIeDSJZ4uUfn9mshE3oszq6YfwONWU9mXIPmvrbO9gaLQJU8DZ4AROERiZAdoZ
ND7aQCowAH/G165k010A8+AYNM7XjT43ofxbsKrOgZq0I0FHJzVR3fqU4ePRL+25
ebyMxXbCaq6LZOnOGkJxarbDtGbaOQhu8BGp7kWKzjIQXMNF6qnc6Tvtb214JN/q
O4qAYDBNT533tXHupAYeZf38r/CnTrbQHZaqsz64w2QK0K/YgFu2c0qHEmT8bJgt
ldrWx162x9blU/x/PMn+lBR2EANl9ex5fwIDAQAB
-----END RSA PUBLIC KEY-----
8 changes: 8 additions & 0 deletions examples/signature_provider/dat/p1_cert0_2048.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAvraadhXvAoa41bJQp07yGRz4pzy3BIg/kVO/Ypp2gQvw7uSPnLxz
6UhHUZjB3uaer7XTQy2PKMJ+yZ/Qj9pPcnJhz8w5WVVKjzGN3c6OH8nDOvJkt+Qe
AXLqkxtqa/rhZTxN0d1KwFjOJONqrhrBSzSsEKPbpik7jDJwAcUbwY+e+eBukEA+
KxH4s9h0SUiRbeUDgRVCXkA4ISVQjtL79HW4bghl0FwQ+JE6z4Hk1Xo2B9RA7lbY
E48a3I7HyGhV6vYrIA8RrPCT/vdR6VE+8N79YjoVLo3aLZNBywKMlRF9gIMOBDVT
lR8f77+tj16yJC1ItfvruijkbWswsKYqSQIDAQAB
-----END RSA PUBLIC KEY-----
28 changes: 28 additions & 0 deletions examples/signature_provider/hsm/hsm_k0_cert0_2048.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCku4PI1IBXyIh3
clvkoTWYqWhD93aHDGkboSTcqnkQQcKN9Dg+oFiZJ8h4NIlni5R+f2ayETeizOrp
h/A41ZT2Zcg+a+ts72BotAlTwNngBE4RGJkB2hk0PtpAKjAAf8bXrmTTXQDz4Bg0
zteNPjeh/Fuwqs6BmrQjQUcnNVHd+pTh49Ev7bl5vIzFdsJqrotk6c4aQnFqtsO0
Zto5CG7wEanuRYrOMhBcw0XqqdzpO+1vbXgk3+o7ioBgME1Pnfe1ce6kBh5l/fyv
8KdOttAdlqqzPrjDZArQr9iAW7ZzSocSZPxsmC2V2tbHXrbH1uVT/H88yf6UFHYQ
A2X17Hl/AgMBAAECggEAbB/IOCGCvBubtwsQ1dgaXcGT9kiPO8UhmEkE8PHT1J/V
G2eZI0IL5Tr/kiapqZUsOntU5Lv4UJs/9ViMjEFkLPZRoOck97OHDDJfjOGgIDGz
K/WBOH323RwEFOmb6Df2Q8rr0u/QmEIWoVLCmKqlyWTiqery8I6ifiFymoGc4p1w
6Y6+PkGjFxrK93EIIx1Jp9iz//tHooPQ8R9uU9A53KutsQe0MquYTfZi92rTwQvr
BhuPIpBN7yDZP244/o31NOzQjfomNlluGjnPLmNofJE8zi8SJfoGn0/f95safCRQ
nQuQUcOptOrVVGA9vKrmRvrFbgHU4DRWscNYrNp+AQKBgQDZO6I+hJOEgMkGnrSm
SUifuZl+e1pZAyRscx2bJhKIEjoayWVJUC8e3usl5E44eZnHVGbscE9mp085p/AX
jmvCXy6Ccemz4V9XZ4eBf7cFOFm1RcE2P6B5ZCsvT15Y6GrsoEnJ5oUk99nkzAq8
zw1STawWTNIkAjyzBsgTuqAHnwKBgQDCIWDOcCBB3tNsJJeMg3FdwqDwljLAGc28
35Z5L9IpEC4+Rh+YCI7ye2yFQdYTrZOCH79WWHEu+qX37Fbq4g2rQBCjN21gR2Un
VQcoVKxWrdtx4lmoSYMHZNymGYwWm5d+QJ1Iudm86d4Ime6aDkF8ov41XvOxzaJN
Wt79lFvCIQKBgQCIDpCcpX6bc+n0inxM1gN1ftKDZJD+xTgP8L2vSdY7gWcBFfip
RV5t8GLJNchEGO1W6icYmXMxsUKust9ucZZOhDzmGKCuOE71uHMnia1AyL1vCsRr
zMgen71ogUZvWwp1MCNnIEluEQpZAe8LuIb4cIuC4BSR1xDbdDjmGnJWswKBgGbB
Bh2fCePzztLB95l/hYUMXOWbitdVkSm060/P+RyVHPUHZvexKAC/RayvMWIPETHi
HgPVImusbibxaPxAlN2dNnE+CF3azHbqMbSuRN5IfgwktDI4XuuN/qDIivb4elJw
XxA8lzzASS8iU0Il45HWMFoNnU3yu0LYo4lzerIhAoGAdc7Op5SNGJdzLo6ynUab
HAIzaYcEw2uUU+GGjNnzflxko0tTcbj35D/xtXBMG036JwfbK5t6A1JLE1XPt2op
kzFj/QN4CyUG7Twjt+CKGmSgPb+qYZ6IKjoiOOh1bN9ozdjbaf6cgK6Nwrwgfmu7
VJhEBdSKjs9m0yMF8YIVSs4=
-----END PRIVATE KEY-----
28 changes: 28 additions & 0 deletions examples/signature_provider/hsm/hsm_k1_cert0_2048.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+tpp2Fe8ChrjV
slCnTvIZHPinPLcEiD+RU79imnaBC/Du5I+cvHPpSEdRmMHe5p6vtdNDLY8own7J
n9CP2k9ycmHPzDlZVUqPMY3dzo4fycM68mS35B4BcuqTG2pr+uFlPE3R3UrAWM4k
42quGsFLNKwQo9umKTuMMnABxRvBj5754G6QQD4rEfiz2HRJSJFt5QOBFUJeQDgh
JVCO0vv0dbhuCGXQXBD4kTrPgeTVejYH1EDuVtgTjxrcjsfIaFXq9isgDxGs8JP+
91HpUT7w3v1iOhUujdotk0HLAoyVEX2Agw4ENVOVHx/vv62PXrIkLUi1++u6KORt
azCwpipJAgMBAAECggEBAIdSPktnyM38Fg7blcsBg1s6aV0RAbPfkWtnBzfJ7igm
9vArkZNfTMfMl35Ya8fjz9lRpPPX0erUBu69zVklSJYmfyzY9iBjGqJ8QPOP6ty3
ZyXedITfAkN47OUw4NR5kZEptvYglTfiS3N1Qm8DYQAiAa1U9zfxreUOrNc0qzst
mSJ2nZKkoFaXK1D2HHIJjpfj8vYY+TPSqHkhnlWEwBcW0054OU4xkAnISvlfMWbs
6Y/n7rqXHNPs3jFi1Z+DjUwry26xtXBs7OkwEb6QLDpaExGHdviUAgYRNG/l+kqv
GIQZJaaFZkKzaJFm7IUStE7vyasmk7S3jC1PILhNdZkCgYEA66RhucsqRE8rP+Os
6+bly7hJ6cse7UmpdKHQmoDQRr9XF3ybnq2u716SIGNQrx0LVtsIr6mdKMr6i5Vs
mPo2vwlYlR8fAc/SxUOl/U/BWbkAVxVVlNFIY2oP1tUW04+EJ0z95k5BpjPT6JV1
C9eHqwf/sqYjOAOknq9naHO2gVMCgYEAzzCLuyjv3TFJ5y0+O0Gpy8/oC+z4Tpoc
gP8X+zywLUwou+OcDqfq/Firsjki+vU66V2x0mnUsjTfo1v1le0BSGbNCAuiKdu3
U9hpl4zEwyvsAh4E1frjnLzeDTlbQX2OdtRC1KEGzD3GxxC+48H+5j8RsZ2O9iF/
JdGYSeXxZnMCgYEA5D/o7WfO/DXXhd5KbILOykMrTUwUG/LDMpdfEZl+pVjHypdH
wi8oiPKJBthMmiK/DhXCVy0rbw0WHUjS1WdgyjEKXf+0MDQXTD7XtQOhHQCnRLME
n88MmEdvKkBkCO82Kj9YnNHmo1AGjn7ezmaqIk/wLSLicGqO9aqftryG5sMCgYBB
kvXGiJBSC3V+az1U99VLokOo8pksF26KDTKD25NO4tnJjaIoqVCgCVheEeNWViMN
FRBgrgoZVM6rH0G878QGLDMcJsJuSRHewZG5212y/8W0bdfN+ZfsVYJZ4RtWwOxE
A64bKdPC9JJjEpO39gA80x1Af8NtdvCNAacXTGV4rQKBgE6QRKaI7gv14qK081di
XsAorBz9ST9MBTjsmrp1pvOksmFD/8lXoINXNUPQLFDm+W0tkYF0RAcvAa2mv4lE
j9Hb5/sJgfaXB+r8IbIEZG+Sslve96FJ0tprH5Jw1n7wnrq1JH+/Ejb932Lok7dB
LJecj7/NyWIc1LX08JBqrDpX
-----END PRIVATE KEY-----
79 changes: 79 additions & 0 deletions examples/signature_provider/hsm/sahsm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# Copyright 2020-2023 NXP
#
# SPDX-License-Identifier: BSD-3-Clause

"""Module represent a customer-specific HSM system."""
import base64
import os

from flask import Flask, Response, jsonify, request

from spsdk import crypto

APP = Flask(__name__)
THIS_DIR = os.path.dirname(__file__)


@APP.route("/signer/<int:num>", methods=["GET"])
def signer(num: int) -> Response:
"""Route (API) that performing the signing.
:param num: Index of the key to use (rot_id)
:return: Signature wrapped in json, encoded in base64
"""
private_key = load_private_key(num)
data_to_sign = base64.b64decode(request.args["data"])

signature = sign_data(private_key, data_to_sign)
data = base64.b64encode(signature)
return jsonify({"signature": data.decode("utf-8")})


@APP.route("/verifier/<int:num>", methods=["GET"])
def verifier(num: int) -> Response:
"""Route (API) that performing the verification.
:param num: Index of the key to use (rot_id)
:return: Verification status(true/false) wrapped in json
"""
private_key = load_private_key(num)
public_key = private_key.public_key()

public_key_bytes = base64.b64decode(request.args["public_key"])
request_public_key = crypto.loaders.load_public_key_from_data(public_key_bytes)
assert isinstance(request_public_key, crypto.RSAPublicKey)
is_matching = public_key.public_numbers().n == request_public_key.public_numbers().n
return jsonify({"is_matching": is_matching})


def sign_data(private_key: crypto.RSAPrivateKey, data: bytes) -> bytes:
"""Sign given data with private key.
:param private_key: Private key to be used for signing
:param data: Data to be signed
:return: Signature as bytes
"""
return private_key.sign(
data=data,
padding=crypto.padding.PKCS1v15(),
algorithm=crypto.hashes.SHA256(),
)


def load_private_key(num: int) -> crypto.RSAPrivateKey:
"""Create an instance of RSAPrivateKey by its index.
:param num: Index of the key to use (rot_id)
"""
private_key_file = os.path.join(THIS_DIR, f"hsm_k{num}_cert0_2048.pem")
private_key = crypto.load_private_key(private_key_file)
# in this example we assume RSA keys
assert isinstance(private_key, crypto.RSAPrivateKey)
return private_key


if __name__ == "__main__":
APP.run(debug=True)

0 comments on commit 85b6e0d

Please sign in to comment.