Skip to content

Commit

Permalink
Enhancing existing attestation scheme with additional information
Browse files Browse the repository at this point in the history
- Implemented new attestation protocol in firmware
- Moved attestation context definition to attestation header file
- Updated admin tooling to gather and validate new attestation format, keeping support for legacy format
- Factored out attestation gathering logic from HSM2Dongle
- New semantics for code hash and public key gathering functions in existing endorsement module
- Additional endorsement module functions to allow for envelope gathering
- New platform module to provide platform id and timestamp
- Added and updated unit tests
- Updated attestation documentation
  • Loading branch information
amendelzon committed Nov 22, 2024
1 parent 9668e49 commit ac8ed5c
Show file tree
Hide file tree
Showing 21 changed files with 720 additions and 202 deletions.
47 changes: 32 additions & 15 deletions docs/attestation.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,17 @@ As a consequence of the aforementioned features, this message guarantees that th

### Signer attestation

To generate the attestation, the Signer uses the configured attestation scheme to sign a message containing a predefined header (`HSM:SIGNER:5.3`) and the `sha256sum` of the concatenation of the authorized public keys (see the [protocol](./protocol.md) for details on this) lexicographically ordered by their UTF-encoded derivation path. This message guarantees that the device is running a specific version of the Signer and that those keys are in control of the ledger device.
To generate the attestation, the Signer uses the configured attestation scheme to sign a message generated by the concatenation of:

- A predefined header (`POWHSM:5.4::`).
- A 3-byte platform identifier, which for Ledger is exactly the ASCII characters `led`.
- A 32 byte user-defined value. By default, the attestation generation client supplies the latest RSK block hash as this value, so it can then be used as a minimum timestamp reference for the attestation generation.
- A 32 byte value that is generated by computing the `sha256sum` of the concatenation of the authorized public keys (see the [protocol](./protocol.md) for details on this) lexicographically ordered by their UTF-encoded derivation path.
- A 32 byte value denoting the device's current known best block hash for the Rootstock network.
- An 8 byte value denoting the leading bytes of the latest authorised signed Bitcoin transaction hash.
- An 8 byte value denoting a big-endian unix timestamp. For Ledger, this is always zero.

This message guarantees that the device is running a specific version of the Signer and that those keys are in control of the ledger device. The additional fields aid in auditing a device's state at the time the attestation is gathered (e.g., for firmware updates).

## Attestation file format

Expand Down Expand Up @@ -101,7 +111,7 @@ The output of the attestation process is a JSON file with a proprietary structur
},
{
"name": "signer",
"message": "48534d3a5349474e45523a332e30a2316e4c4e07e77ae65c74574452f330ed62752ba4c66f9c2101836d7b36cef2",
"message": "504f5748534d3a352e343a3a6c656413c3581aa97c8169d3994e9369c11ebd63bcf123d0671634f21b568983d3291687fd9b1f4aa83e348906e2efd6cbed98e39d17aea4c03d73f30e99d602d67633bdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b659a04529d6811dd0000000000000000",
"signature": "30440220154bb544fe00df5635c03618ee9614d50933fe7c9226d8efce55f1a40832681402206289dab7b8d6700e048b602ac03516e0e6a1609796fc27c440848d072af71c2a",
"signed_by": "attestation",
"tweak": "e1baa18564fc0c2c70ac4019609c6db643adbf12711c8b319f838e6a74b0da2c"
Expand Down Expand Up @@ -158,23 +168,30 @@ to then obtain the following sample output:
Using 0490f5c9d15a0134bb019d2afd0bf297149738459706e7ac5be4abc350a1f818057224fce12ec9a65de18ec34d6e8c24db927835ea1692b14c32e9836a75dad609 as root authority
--------------------------------------------------------------------------------------------------------
UI verified with:
UD value: c4207b260c5b6964190568e528ec0b212a70e512ed6bdcef5e192362852a3839
Derived public key (m/44'/0'/0'/0/0): 03198eb60255fefc3478d0a78c11f5124c938f66fdaa62f9e9c543c6ced031ef37
Authorized signer hash: e1baa18564fc0c2c70ac4019609c6db643adbf12711c8b319f838e6a74b0da2c
UD value: 13c3581aa97c8169d3994e9369c11ebd63bcf123d0671634f21b568983d32916
Derived public key (m/44'/0'/0'/0/0): 0254464d36eaa08a2c31a80eb902e7400563f403c85ef51dd73aaadb57967b61e8
Authorized signer hash: cc3c55563a4fa50d973faf704d7ef4f272b99ed7e0e0848457dd60be7d3df4b5
Authorized signer iteration: 1
Installed UI hash: 17f2129265b071e3d8658a549cd60720c86e34c7a6b81d517ffef123c8425f19
Installed UI hash: 7674c4870ff06ace61d468df8af521be6cc40e86ca6a6b732453801e6b7adf9d
Installed UI version: 5.4
--------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------
Signer verified with public keys:
m/44'/0'/0'/0/0: 03198eb60255fefc3478d0a78c11f5124c938f66fdaa62f9e9c543c6ced031ef37
m/44'/1'/0'/0/0: 0309fe4c9a803658c1d1c0c19f2d841e34306d172f0bb092431ace7bbda334e902
m/44'/1'/1'/0/0: 023ac8c77507fdcb7581ce3ee366a7b09791b54377af67f75e1a159737f4f77fe7
m/44'/1'/2'/0/0: 02583d0dec06114cc0a19883398652d8f87af0175f7d7c2c97417622341e06560c
m/44'/137'/0'/0/0: 03458e7f8f7885f0b0648a8e2e899fe838a7f93da0028634689438e460d3ba614f
m/44'/137'/1'/0/0: 03e27a65c9e6ff0d3fc4085aa84f8d7ec467edf6ae6b30ed40d96d4344b516f4c6
Hash: a2316e4c4e07e77ae65c74574452f330ed62752ba4c66f9c2101836d7b36cef2
Installed Signer hash: e1baa18564fc0c2c70ac4019609c6db643adbf12711c8b319f838e6a74b0da2c
m/44'/0'/0'/0/0: 0254464d36eaa08a2c31a80eb902e7400563f403c85ef51dd73aaadb57967b61e8
m/44'/1'/0'/0/0: 02a7171ba5fcdf9ae8a32b733cbe748b6007b4633939ba1c8baca074e9358a281a
m/44'/1'/1'/0/0: 022e777db5856568da55947c1a60df4ec28b8fb27ea182de54575b3aadc4559932
m/44'/1'/2'/0/0: 0307455520c1b365436741c98ddc987c8ed7adddf67b8b69e5763f930c0131727e
m/44'/137'/0'/0/0: 02ecdf31ca81e7c5a2949dad38536676eee2647ec2e41c0771cd4e918b5c2fc4f8
m/44'/137'/1'/0/0: 0345ac500d260c1f6794b21fad8acce66548fee7a463befd5a0ec5bb73b9ae4df1
Hash: 72237ee55064aebd5ab13d179c61bfb41c5b1d2ed7e018f8de46a7262c8cf1ec
Installed Signer hash: cc3c55563a4fa50d973faf704d7ef4f272b99ed7e0e0848457dd60be7d3df4b5
Installed Signer version: 5.4
Platform: led
UD value: 13c3581aa97c8169d3994e9369c11ebd63bcf123d0671634f21b568983d32916
Best block: bdcb3c17c7aee714cec8ad900341bfd987b452280220dcbd6e7191f67ea4209b
Last transaction signed: 659a04529d6811dd
Timestamp: 0000000000000000
---------------------------------------------------------------------------------------
```

Expand Down
18 changes: 17 additions & 1 deletion firmware/src/hal/include/hal/endorsement.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ bool endorsement_sign(uint8_t* msg,
uint8_t* signature_out,
uint8_t* signature_out_length);

/**
* @brief Gets a pointer to the last signed envelope
*
* @return a pointer to a buffer containing the envelope,
* or NULL if no envelope is available.
*/
uint8_t* endorsement_get_envelope();

/**
* @brief Gets the length of the last signed envelope
*
* @return the byte length of the last signed envelope,
* or ZERO if no envelope is available.
*/
size_t endorsement_get_envelope_length();

/**
* @brief Grabs the hash of the currently running code
*
Expand Down Expand Up @@ -99,7 +115,7 @@ extern attestation_id_t attestation_id;
*/
bool endorsement_init(char* att_file_path);

#elif defined(HSM_PLATFORM_SGX)
#elif defined(HSM_PLATFORM_SGX) || defined(HSM_PLATFORM_LEDGER)

/**
* @brief Initializes the endorsement module
Expand Down
13 changes: 13 additions & 0 deletions firmware/src/hal/include/hal/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include <stdint.h>
#include <stdbool.h>

// Size in bytes of a platform id
#define PLATFORM_ID_LENGTH 3

/**
* @brief Perform the platform-specific version of memmove
*
Expand All @@ -42,6 +45,16 @@ void platform_memmove(void *dst, const void *src, unsigned int length);
*/
void platform_request_exit();

/**
* @brief Get the current platform id
*/
const char *platform_get_id();

/**
* @brief Get the current timestamp
*/
uint64_t platform_get_timestamp();

/**
* X86 specific headers
*/
Expand Down
23 changes: 23 additions & 0 deletions firmware/src/hal/ledger/src/endorsement.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@
// Index of the ledger endorsement scheme
#define ENDORSEMENT_SCHEME_INDEX 2

static bool sign_performed;

bool endorsement_init() {
sign_performed = false;
return true;
}

uint8_t* endorsement_get_envelope() {
return NULL;
}

size_t endorsement_get_envelope_length() {
return 0;
}

bool endorsement_sign(uint8_t* msg,
size_t msg_size,
uint8_t* signature_out,
Expand All @@ -41,11 +56,15 @@ bool endorsement_sign(uint8_t* msg,
*signature_out_length =
os_endorsement_key2_derive_sign_data(msg, msg_size, signature_out);

sign_performed = true;
return true;
}

bool endorsement_get_code_hash(uint8_t* code_hash_out,
uint8_t* code_hash_out_length) {
if (!sign_performed) {
return false;
}

if (*code_hash_out_length < HASH_LENGTH) {
return false;
Expand All @@ -57,6 +76,10 @@ bool endorsement_get_code_hash(uint8_t* code_hash_out,

bool endorsement_get_public_key(uint8_t* public_key_out,
uint8_t* public_key_out_length) {
if (!sign_performed) {
return false;
}

if (*public_key_out_length < PUBKEY_UNCMP_LENGTH) {
return false;
}
Expand Down
8 changes: 8 additions & 0 deletions firmware/src/hal/ledger/src/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,12 @@ void platform_request_exit() {
}
}
END_TRY_L(exit);
}

const char *platform_get_id() {
return "led";
}

uint64_t platform_get_timestamp() {
return (uint64_t)0;
}
8 changes: 8 additions & 0 deletions firmware/src/hal/x86/src/endorsement.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,14 @@ bool endorsement_init(char* att_file_path) {
return true;
}

uint8_t* endorsement_get_envelope() {
return NULL;
}

size_t endorsement_get_envelope_length() {
return 0;
}

bool endorsement_sign(uint8_t* msg,
size_t msg_size,
uint8_t* signature_out,
Expand Down
11 changes: 10 additions & 1 deletion firmware/src/hal/x86/src/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "hal/log.h"

#include <string.h>
#include <time.h>

void platform_memmove(void *dst, const void *src, unsigned int length) {
memmove(dst, src, length);
Expand All @@ -34,4 +35,12 @@ void platform_memmove(void *dst, const void *src, unsigned int length) {
void platform_request_exit() {
// Currently unsupported, just log the call
LOG("platform_request_exit called\n");
}
}

const char *platform_get_id() {
return "x86";
}

uint64_t platform_get_timestamp() {
return (uint64_t)time(NULL);
}
2 changes: 2 additions & 0 deletions firmware/src/ledger/signer/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@

// HAL includes
#include "hal/communication.h"
#include "hal/endorsement.h"

// The interval between two subsequent ticker events in milliseconds. This is
// assumed to be 100ms according to the nanos-secure-sdk documentation.
Expand Down Expand Up @@ -192,6 +193,7 @@ __attribute__((section(".boot"))) int main(int argc, char **argv) {

// HAL modules initialization
communication_init(G_io_apdu_buffer, sizeof(G_io_apdu_buffer));
endorsement_init();

// HSM context initialization
hsm_init();
Expand Down
Loading

0 comments on commit ac8ed5c

Please sign in to comment.