Implement Ledger-PKI

- Update src code to adapt to new API 'os_pki_verify'
- Support both Ledger-PKI and legacy method
This commit is contained in:
Charles-Edouard de la Vergne
2024-06-11 10:55:11 +02:00
parent 1ac75092da
commit 2008307c0c
8 changed files with 291 additions and 217 deletions

View File

@@ -9,6 +9,9 @@
#include "network.h"
#include "public_keys.h"
#include "manage_asset_info.h"
#ifdef HAVE_LEDGER_PKI
#include "os_pki.h"
#endif
#define TYPE_SIZE 1
#define VERSION_SIZE 1
@@ -50,19 +53,29 @@ void handleProvideNFTInformation(uint8_t p1,
UNUSED(tx);
UNUSED(flags);
uint8_t hash[INT256_LENGTH];
cx_ecfp_public_key_t nftKey;
nftInfo_t *nft = NULL;
size_t offset = 0;
size_t payloadSize = 0;
uint8_t collectionNameLength = 0;
uint64_t chain_id = 0;
uint8_t signatureLen = 0;
cx_err_t error = CX_INTERNAL_ERROR;
#ifdef HAVE_NFT_STAGING_KEY
uint8_t valid_keyId = STAGING_NFT_METADATA_KEY;
#else
uint8_t valid_keyId = PROD_NFT_METADATA_KEY;
#endif
PRINTF("In handle provide NFTInformation\n");
if ((pluginType != ERC721) && (pluginType != ERC1155)) {
PRINTF("NFT metadata provided without proper plugin loaded!\n");
THROW(0x6985);
}
nftInfo_t *nft = &get_current_asset_info()->nft;
nft = &get_current_asset_info()->nft;
PRINTF("Provisioning currentAssetIndex %d\n", tmpCtx.transactionContext.currentAssetIndex);
size_t offset = 0;
if (dataLength <= HEADER_SIZE) {
PRINTF("Data too small for headers: expected at least %d, got %d\n",
HEADER_SIZE,
@@ -70,34 +83,24 @@ void handleProvideNFTInformation(uint8_t p1,
THROW(APDU_RESPONSE_INVALID_DATA);
}
uint8_t type = workBuffer[offset];
switch (type) {
case TYPE_1:
break;
default:
PRINTF("Unsupported type %d\n", type);
THROW(APDU_RESPONSE_INVALID_DATA);
break;
if (workBuffer[offset] != TYPE_1) {
PRINTF("Unsupported type %d\n", workBuffer[offset]);
THROW(APDU_RESPONSE_INVALID_DATA);
}
offset += TYPE_SIZE;
uint8_t version = workBuffer[offset];
switch (version) {
case VERSION_1:
break;
default:
PRINTF("Unsupported version %d\n", version);
THROW(APDU_RESPONSE_INVALID_DATA);
break;
if (workBuffer[offset] != VERSION_1) {
PRINTF("Unsupported version %d\n", workBuffer[offset]);
THROW(APDU_RESPONSE_INVALID_DATA);
}
offset += VERSION_SIZE;
uint8_t collectionNameLength = workBuffer[offset];
collectionNameLength = workBuffer[offset];
offset += NAME_LENGTH_SIZE;
// Size of the payload (everything except the signature)
size_t payloadSize = HEADER_SIZE + collectionNameLength + ADDRESS_LENGTH + CHAIN_ID_SIZE +
KEY_ID_SIZE + ALGORITHM_ID_SIZE;
payloadSize = HEADER_SIZE + collectionNameLength + ADDRESS_LENGTH + CHAIN_ID_SIZE +
KEY_ID_SIZE + ALGORITHM_ID_SIZE;
if (dataLength < payloadSize) {
PRINTF("Data too small for payload: expected at least %d, got %d\n",
payloadSize,
@@ -124,7 +127,7 @@ void handleProvideNFTInformation(uint8_t p1,
PRINTF("Address: %.*H\n", ADDRESS_LENGTH, workBuffer + offset);
offset += ADDRESS_LENGTH;
uint64_t chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
chain_id = u64_from_BE(workBuffer + offset, CHAIN_ID_SIZE);
// this prints raw data, so to have a more meaningful print, display
// the buffer before the endianness swap
PRINTF("ChainID: %.*H\n", sizeof(chain_id), (workBuffer + offset));
@@ -134,35 +137,18 @@ void handleProvideNFTInformation(uint8_t p1,
}
offset += CHAIN_ID_SIZE;
uint8_t keyId = workBuffer[offset];
const uint8_t *rawKey;
uint8_t rawKeyLen;
PRINTF("KeyID: %d\n", keyId);
switch (keyId) {
#ifdef HAVE_NFT_STAGING_KEY
case STAGING_NFT_METADATA_KEY:
#endif
case PROD_NFT_METADATA_KEY:
rawKey = LEDGER_NFT_METADATA_PUBLIC_KEY;
rawKeyLen = sizeof(LEDGER_NFT_METADATA_PUBLIC_KEY);
break;
default:
PRINTF("KeyID %d not supported\n", keyId);
THROW(APDU_RESPONSE_INVALID_DATA);
break;
if (workBuffer[offset] != valid_keyId) {
PRINTF("Unsupported KeyID %d\n", workBuffer[offset]);
THROW(APDU_RESPONSE_INVALID_DATA);
}
PRINTF("RawKey: %.*H\n", rawKeyLen, rawKey);
offset += KEY_ID_SIZE;
uint8_t algorithmId = workBuffer[offset];
PRINTF("Algorithm: %d\n", algorithmId);
if (algorithmId != ALGORITHM_ID_1) {
PRINTF("Incorrect algorithmId %d\n", algorithmId);
if (workBuffer[offset] != ALGORITHM_ID_1) {
PRINTF("Incorrect algorithmId %d\n", workBuffer[offset]);
THROW(APDU_RESPONSE_INVALID_DATA);
}
offset += ALGORITHM_ID_SIZE;
PRINTF("hashing: %.*H\n", payloadSize, workBuffer);
cx_hash_sha256(workBuffer, payloadSize, hash, sizeof(hash));
@@ -171,7 +157,7 @@ void handleProvideNFTInformation(uint8_t p1,
THROW(APDU_RESPONSE_INVALID_DATA);
}
uint8_t signatureLen = workBuffer[offset];
signatureLen = workBuffer[offset];
PRINTF("Signature len: %d\n", signatureLen);
if (signatureLen < MIN_DER_SIG_SIZE || signatureLen > MAX_DER_SIG_SIZE) {
PRINTF("SignatureLen too big or too small. Must be between %d and %d, got %d\n",
@@ -187,17 +173,21 @@ void handleProvideNFTInformation(uint8_t p1,
THROW(APDU_RESPONSE_INVALID_DATA);
}
CX_ASSERT(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, rawKey, rawKeyLen, &nftKey));
if (!cx_ecdsa_verify_no_throw(&nftKey,
hash,
sizeof(hash),
(uint8_t *) workBuffer + offset,
signatureLen)) {
#ifndef HAVE_BYPASS_SIGNATURES
PRINTF("Invalid NFT signature\n");
THROW(APDU_RESPONSE_INVALID_DATA);
error = check_signature_with_pubkey("NFT Info",
hash,
sizeof(hash),
LEDGER_NFT_METADATA_PUBLIC_KEY,
sizeof(LEDGER_NFT_METADATA_PUBLIC_KEY),
#ifdef HAVE_LEDGER_PKI
CERTIFICATE_PUBLIC_KEY_USAGE_NFT_METADATA,
#endif
(uint8_t *) (workBuffer + offset),
signatureLen);
#ifndef HAVE_BYPASS_SIGNATURES
if (error != CX_OK) {
THROW(APDU_RESPONSE_INVALID_DATA);
}
#endif
G_io_apdu_buffer[0] = tmpCtx.transactionContext.currentAssetIndex;
validate_current_asset_info();