mirror of https://github.com/wolfSSL/wolfBoot.git
372 lines
12 KiB
C
372 lines
12 KiB
C
/* app_mcxn.c
|
|
*
|
|
* Copyright (C) 2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfBoot.
|
|
*
|
|
* wolfBoot is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfBoot is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include "fsl_clock.h"
|
|
#include "fsl_gpio.h"
|
|
#include "fsl_port.h"
|
|
|
|
#include "target.h"
|
|
#include "wolfboot/wolfboot.h"
|
|
#include "printf.h"
|
|
|
|
#ifdef WOLFCRYPT_SECURE_MODE
|
|
#include "wolfssl/wolfcrypt/types.h"
|
|
#include "wolfssl/wolfcrypt/random.h"
|
|
#endif
|
|
|
|
#ifdef WOLFCRYPT_TZ_PSA
|
|
#include "psa/crypto.h"
|
|
#include "psa/error.h"
|
|
#include "psa/initial_attestation.h"
|
|
#include "wolfssl/wolfcrypt/types.h"
|
|
#endif
|
|
|
|
extern void hal_init(void);
|
|
|
|
static void gpio_init_output(GPIO_Type *gpio, PORT_Type *port,
|
|
clock_ip_name_t gpio_clock,
|
|
clock_ip_name_t port_clock, uint32_t pin,
|
|
uint8_t initial_level)
|
|
{
|
|
const port_pin_config_t pin_config = {
|
|
.pullSelect = kPORT_PullDisable,
|
|
#if defined(FSL_FEATURE_PORT_PCR_HAS_PULL_VALUE) && FSL_FEATURE_PORT_PCR_HAS_PULL_VALUE
|
|
.pullValueSelect = kPORT_LowPullResistor,
|
|
#endif
|
|
#if defined(FSL_FEATURE_PORT_HAS_SLEW_RATE) && FSL_FEATURE_PORT_HAS_SLEW_RATE
|
|
.slewRate = kPORT_FastSlewRate,
|
|
#endif
|
|
#if defined(FSL_FEATURE_PORT_HAS_PASSIVE_FILTER) && FSL_FEATURE_PORT_HAS_PASSIVE_FILTER
|
|
.passiveFilterEnable = kPORT_PassiveFilterDisable,
|
|
#endif
|
|
#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN
|
|
.openDrainEnable = kPORT_OpenDrainDisable,
|
|
#endif
|
|
#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH
|
|
.driveStrength = kPORT_LowDriveStrength,
|
|
#endif
|
|
#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH1) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH1
|
|
.driveStrength1 = kPORT_LowDriveStrength,
|
|
#endif
|
|
.mux = kPORT_MuxAlt0,
|
|
#if defined(FSL_FEATURE_PORT_HAS_INPUT_BUFFER) && FSL_FEATURE_PORT_HAS_INPUT_BUFFER
|
|
.inputBuffer = kPORT_InputBufferEnable,
|
|
#endif
|
|
#if defined(FSL_FEATURE_PORT_HAS_INVERT_INPUT) && FSL_FEATURE_PORT_HAS_INVERT_INPUT
|
|
.invertInput = kPORT_InputNormal,
|
|
#endif
|
|
#if defined(FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK) && FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK
|
|
.lockRegister = kPORT_UnlockRegister
|
|
#endif
|
|
};
|
|
const gpio_pin_config_t gpio_config = {
|
|
.pinDirection = kGPIO_DigitalOutput,
|
|
.outputLogic = initial_level,
|
|
};
|
|
|
|
CLOCK_EnableClock(gpio_clock);
|
|
CLOCK_EnableClock(port_clock);
|
|
GPIO_PinInit(gpio, pin, &gpio_config);
|
|
PORT_SetPinConfig(port, pin, &pin_config);
|
|
}
|
|
|
|
#ifdef WOLFCRYPT_TZ_PSA
|
|
#define LINE_LEN 16
|
|
|
|
static void print_hex(const uint8_t *buffer, uint32_t length, int dumpChars)
|
|
{
|
|
uint32_t i, sz;
|
|
|
|
if (!buffer) {
|
|
wolfBoot_printf("\tNULL\r\n");
|
|
return;
|
|
}
|
|
|
|
while (length > 0) {
|
|
sz = length;
|
|
if (sz > LINE_LEN)
|
|
sz = LINE_LEN;
|
|
|
|
wolfBoot_printf("\t");
|
|
for (i = 0; i < LINE_LEN; i++) {
|
|
if (i < sz)
|
|
wolfBoot_printf("%02x ", buffer[i]);
|
|
else
|
|
wolfBoot_printf(" ");
|
|
}
|
|
if (dumpChars) {
|
|
wolfBoot_printf("| ");
|
|
for (i = 0; i < sz; i++) {
|
|
if (buffer[i] > 31 && buffer[i] < 127)
|
|
wolfBoot_printf("%c", buffer[i]);
|
|
else
|
|
wolfBoot_printf(".");
|
|
}
|
|
}
|
|
wolfBoot_printf("\r\n");
|
|
|
|
buffer += sz;
|
|
length -= sz;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(WOLFBOOT_ATTESTATION_TEST) && defined(WOLFCRYPT_TZ_PSA)
|
|
|
|
/* Read a CBOR bstr at *offset; sets *data and *data_len, advances *offset. */
|
|
static int cbor_get_bstr(const uint8_t *buf, size_t buf_len, size_t *offset,
|
|
const uint8_t **data, size_t *data_len)
|
|
{
|
|
uint8_t b;
|
|
size_t len;
|
|
if (*offset >= buf_len) return -1;
|
|
b = buf[(*offset)++];
|
|
if ((b >> 5) != 2) return -1; /* must be CBOR major type 2 (bstr) */
|
|
switch (b & 0x1F) {
|
|
case 24:
|
|
if (*offset >= buf_len) return -1;
|
|
len = buf[(*offset)++]; break;
|
|
case 25:
|
|
if (*offset + 2 > buf_len) return -1;
|
|
len = ((size_t)buf[*offset] << 8) | buf[*offset + 1];
|
|
*offset += 2; break;
|
|
default:
|
|
if ((b & 0x1F) > 23) return -1; /* rejects AI>=26 */
|
|
len = b & 0x1F;
|
|
}
|
|
if (*offset + len > buf_len) return -1;
|
|
*data = buf + *offset;
|
|
*data_len = len;
|
|
*offset += len;
|
|
return 0;
|
|
}
|
|
|
|
/* Maximum fixed bytes in a COSE_Sign1 Sig_Structure before variable content:
|
|
* 1 (array(4) tag) + 1 (tstr(10) tag) + 10 ("Signature1") +
|
|
* 3 (max bstr hdr for prot) + 1 (empty-AAD 0x40) + 3 (max bstr hdr for payload)
|
|
*/
|
|
#define COSE_SIGN1_TBS_FIXED_OVERHEAD (1 + 1 + 10 + 3 + 1 + 3)
|
|
|
|
/* Write a CBOR bstr length header into buf; returns number of bytes written. */
|
|
static int cbor_put_bstr_hdr(uint8_t *buf, size_t len)
|
|
{
|
|
if (len <= 23) {
|
|
buf[0] = 0x40 | (uint8_t)len;
|
|
return 1;
|
|
}
|
|
if (len <= 0xFF) {
|
|
buf[0] = 0x58; buf[1] = (uint8_t)len;
|
|
return 2;
|
|
}
|
|
if (len > 0xFFFF)
|
|
return -1;
|
|
buf[0] = 0x59; buf[1] = (uint8_t)(len >> 8);
|
|
buf[2] = (uint8_t)len;
|
|
return 3;
|
|
}
|
|
|
|
static int run_attest_verify_test(void)
|
|
{
|
|
static const uint8_t challenge[PSA_INITIAL_ATTEST_CHALLENGE_SIZE_32] = {
|
|
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
|
|
0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,
|
|
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
|
|
0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20
|
|
};
|
|
static uint8_t token[1024];
|
|
static uint8_t tbs[1024]; /* Sig_Structure buffer */
|
|
uint8_t pubkey[65];
|
|
uint8_t hash[32];
|
|
size_t token_len = sizeof(token);
|
|
size_t pubkey_len = sizeof(pubkey);
|
|
size_t hash_len = 0;
|
|
size_t tbs_len = 0;
|
|
const uint8_t *prot_bytes, *payload_bytes, *sig_bytes;
|
|
size_t prot_len, payload_len, sig_len;
|
|
size_t off = 0;
|
|
int hdr;
|
|
psa_status_t st;
|
|
psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT;
|
|
psa_key_id_t key_id;
|
|
|
|
wolfBoot_printf("Start attestation verify test\r\n");
|
|
|
|
/* 1. Generate token — also caches the IAK public key on the secure side */
|
|
st = psa_initial_attest_get_token(challenge, sizeof(challenge),
|
|
token, sizeof(token), &token_len);
|
|
if (st != PSA_SUCCESS) {
|
|
wolfBoot_printf("attest_verify: get_token failed (%d)\r\n", (int)st);
|
|
return -1;
|
|
}
|
|
wolfBoot_printf("attest_verify: token_len=%lu\r\n", (unsigned long)token_len);
|
|
print_hex(token, (uint32_t)token_len, 1);
|
|
|
|
/* 2. Retrieve IAK public key via PSA attestation service (read-once) */
|
|
st = psa_initial_attest_get_iak_pubkey(pubkey, sizeof(pubkey), &pubkey_len);
|
|
if (st != PSA_SUCCESS) {
|
|
wolfBoot_printf("attest_verify: get_iak_pubkey failed (%d)\r\n", (int)st);
|
|
return -1;
|
|
}
|
|
wolfBoot_printf("attest_verify: IAK pubkey (%lu bytes):\r\n",
|
|
(unsigned long)pubkey_len);
|
|
print_hex(pubkey, (uint32_t)pubkey_len, 1);
|
|
|
|
/* 3. Parse COSE_Sign1: 84 | prot_bstr | A0 | payload_bstr | sig_bstr */
|
|
if (off >= token_len || token[off++] != 0x84) {
|
|
wolfBoot_printf("attest_verify: bad array tag\r\n"); return -1;
|
|
}
|
|
if (cbor_get_bstr(token, token_len, &off, &prot_bytes, &prot_len) != 0 ||
|
|
off >= token_len || token[off++] != 0xA0 ||
|
|
cbor_get_bstr(token, token_len, &off, &payload_bytes, &payload_len) != 0 ||
|
|
cbor_get_bstr(token, token_len, &off, &sig_bytes, &sig_len) != 0 ||
|
|
sig_len != 64) {
|
|
wolfBoot_printf("attest_verify: COSE parse failed\r\n"); return -1;
|
|
}
|
|
|
|
/* 4. Reconstruct Sig_Structure = ["Signature1", prot_bstr, b"", payload_bstr] */
|
|
if (COSE_SIGN1_TBS_FIXED_OVERHEAD + prot_len + payload_len > sizeof(tbs)) {
|
|
wolfBoot_printf("attest_verify: tbs buffer too small\r\n");
|
|
return -1;
|
|
}
|
|
tbs[tbs_len++] = 0x84; /* array(4) */
|
|
tbs[tbs_len++] = 0x6A; /* tstr(10) */
|
|
memcpy(tbs + tbs_len, "Signature1", 10); tbs_len += 10;
|
|
hdr = cbor_put_bstr_hdr(tbs + tbs_len, prot_len);
|
|
if (hdr < 0) { wolfBoot_printf("attest_verify: cbor hdr failed\r\n"); return -1; }
|
|
tbs_len += hdr;
|
|
memcpy(tbs + tbs_len, prot_bytes, prot_len);
|
|
tbs_len += prot_len;
|
|
tbs[tbs_len++] = 0x40; /* bstr(0): empty AAD */
|
|
hdr = cbor_put_bstr_hdr(tbs + tbs_len, payload_len);
|
|
if (hdr < 0) { wolfBoot_printf("attest_verify: cbor hdr failed\r\n"); return -1; }
|
|
tbs_len += hdr;
|
|
memcpy(tbs + tbs_len, payload_bytes, payload_len);
|
|
tbs_len += payload_len;
|
|
|
|
/* 5. SHA-256 hash of Sig_Structure */
|
|
if (psa_hash_compute(PSA_ALG_SHA_256, tbs, tbs_len,
|
|
hash, sizeof(hash), &hash_len) != PSA_SUCCESS) {
|
|
wolfBoot_printf("attest_verify: hash failed\r\n");
|
|
return -1;
|
|
}
|
|
|
|
/* 6. Import IAK public key and verify ES256 signature (raw R||S, 64 bytes) */
|
|
psa_set_key_type(&attrs, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
|
|
psa_set_key_bits(&attrs, 256);
|
|
psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_VERIFY_HASH);
|
|
psa_set_key_algorithm(&attrs, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
|
|
if (psa_import_key(&attrs, pubkey, pubkey_len, &key_id) != PSA_SUCCESS) {
|
|
psa_reset_key_attributes(&attrs);
|
|
wolfBoot_printf("attest_verify: import_key failed\r\n");
|
|
return -1;
|
|
}
|
|
psa_reset_key_attributes(&attrs);
|
|
st = psa_verify_hash(key_id, PSA_ALG_ECDSA(PSA_ALG_SHA_256),
|
|
hash, hash_len, sig_bytes, sig_len);
|
|
psa_destroy_key(key_id);
|
|
|
|
if (st != PSA_SUCCESS) {
|
|
wolfBoot_printf("attest_verify: FAILED (%d)\r\n", (int)st);
|
|
return -1;
|
|
}
|
|
wolfBoot_printf("attest_verify: IAK signature verified OK\r\n");
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WOLFCRYPT_SECURE_MODE
|
|
static void print_random_number(void)
|
|
{
|
|
uint8_t rnd;
|
|
int ret;
|
|
|
|
ret = wcs_get_random(&rnd, sizeof(rnd));
|
|
if (ret != 0)
|
|
wolfBoot_printf("Random number: generate failed (%d)\n", ret);
|
|
else
|
|
wolfBoot_printf("Today's lucky number: 0x%02x\n", rnd);
|
|
}
|
|
#endif
|
|
|
|
void main(void)
|
|
{
|
|
uint32_t boot_ver;
|
|
|
|
hal_init();
|
|
|
|
#ifdef TZEN
|
|
boot_ver = wolfBoot_nsc_current_firmware_version();
|
|
#else
|
|
boot_ver = wolfBoot_current_firmware_version();
|
|
#endif
|
|
|
|
wolfBoot_printf("Hello from firmware version %d\n", boot_ver);
|
|
|
|
#ifdef WOLFCRYPT_SECURE_MODE
|
|
print_random_number();
|
|
#endif
|
|
|
|
#ifdef WOLFCRYPT_TZ_PSA
|
|
{
|
|
psa_status_t psa_ret = psa_crypto_init();
|
|
|
|
if (psa_ret == PSA_SUCCESS)
|
|
wolfBoot_printf("PSA crypto init ok\r\n");
|
|
else
|
|
wolfBoot_printf("PSA crypto init failed (%d)\r\n", (int)psa_ret);
|
|
}
|
|
#endif
|
|
|
|
#if defined(WOLFBOOT_ATTESTATION_TEST) && defined(WOLFCRYPT_TZ_PSA)
|
|
(void)run_attest_verify_test();
|
|
#endif
|
|
|
|
if (boot_ver == 1) {
|
|
/* Red off */
|
|
gpio_init_output(GPIO0, PORT0, kCLOCK_Gpio0, kCLOCK_Port0, 10U, 1U);
|
|
/* Green off */
|
|
gpio_init_output(GPIO0, PORT0, kCLOCK_Gpio0, kCLOCK_Port0, 27U, 1U);
|
|
/* Blue on */
|
|
gpio_init_output(GPIO1, PORT1, kCLOCK_Gpio1, kCLOCK_Port1, 2U, 0U);
|
|
}
|
|
else {
|
|
/* Red off */
|
|
gpio_init_output(GPIO0, PORT0, kCLOCK_Gpio0, kCLOCK_Port0, 10U, 1U);
|
|
/* Green on */
|
|
gpio_init_output(GPIO0, PORT0, kCLOCK_Gpio0, kCLOCK_Port0, 27U, 0U);
|
|
/* Blue off */
|
|
gpio_init_output(GPIO1, PORT1, kCLOCK_Gpio1, kCLOCK_Port1, 2U, 1U);
|
|
|
|
#ifdef TZEN
|
|
wolfBoot_nsc_success();
|
|
#else
|
|
wolfBoot_success();
|
|
#endif
|
|
}
|
|
|
|
while (1) {
|
|
__asm__ volatile ("wfi");
|
|
}
|
|
}
|