mirror of https://github.com/wolfSSL/wolfBoot.git
324 lines
10 KiB
C
324 lines
10 KiB
C
/* app_max32666.c
|
|
*
|
|
* Test application for wolfBoot on MAX32666FTHR
|
|
*
|
|
* Copyright (C) 2025 wolfSSL Inc.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include "hal.h"
|
|
#include "wolfboot/wolfboot.h"
|
|
#include "printf.h"
|
|
#include "hal/max32666.h"
|
|
|
|
#ifdef WOLFCRYPT_MAX32666_TEST
|
|
#include <wolfssl/wolfcrypt/settings.h>
|
|
#include <wolfssl/wolfcrypt/aes.h>
|
|
#include <wolfssl/wolfcrypt/ecc.h>
|
|
#include <wolfssl/wolfcrypt/random.h>
|
|
#include <wolfssl/wolfcrypt/port/maxim/max3266x.h>
|
|
|
|
/*
|
|
* AES-GCM 256-bit known-answer test
|
|
* Test Case 16 from McGrew & Viega GCM spec (same as wolfcrypt test.c)
|
|
*/
|
|
static int test_aes_gcm_256(void)
|
|
{
|
|
Aes aes;
|
|
int ret;
|
|
byte resultC[60];
|
|
byte resultT[16];
|
|
byte resultP[60];
|
|
|
|
static const byte key[] = {
|
|
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
|
|
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,
|
|
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
|
|
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08
|
|
};
|
|
static const byte iv[] = {
|
|
0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
|
|
0xde, 0xca, 0xf8, 0x88
|
|
};
|
|
static const byte plain[] = {
|
|
0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
|
|
0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
|
|
0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
|
|
0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
|
|
0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
|
|
0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
|
|
0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
|
|
0xba, 0x63, 0x7b, 0x39
|
|
};
|
|
static const byte aad[] = {
|
|
0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
|
|
0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
|
|
0xab, 0xad, 0xda, 0xd2
|
|
};
|
|
static const byte expC[] = {
|
|
0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07,
|
|
0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d,
|
|
0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
|
|
0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa,
|
|
0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d,
|
|
0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
|
|
0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a,
|
|
0xbc, 0xc9, 0xf6, 0x62
|
|
};
|
|
static const byte expT[] = {
|
|
0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
|
|
0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b
|
|
};
|
|
|
|
wolfBoot_printf("AES-GCM-256 test: ");
|
|
|
|
memset(&aes, 0, sizeof(aes));
|
|
ret = wc_AesGcmSetKey(&aes, key, sizeof(key));
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (SetKey: %d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
memset(resultC, 0, sizeof(resultC));
|
|
memset(resultT, 0, sizeof(resultT));
|
|
ret = wc_AesGcmEncrypt(&aes, resultC, plain, sizeof(plain),
|
|
iv, sizeof(iv), resultT, sizeof(resultT),
|
|
aad, sizeof(aad));
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (Encrypt: %d)\n", ret);
|
|
return ret;
|
|
}
|
|
if (memcmp(resultC, expC, sizeof(expC)) != 0) {
|
|
wolfBoot_printf("FAIL (ciphertext mismatch)\n");
|
|
return -1;
|
|
}
|
|
if (memcmp(resultT, expT, sizeof(expT)) != 0) {
|
|
wolfBoot_printf("FAIL (tag mismatch)\n");
|
|
return -1;
|
|
}
|
|
|
|
memset(resultP, 0, sizeof(resultP));
|
|
ret = wc_AesGcmDecrypt(&aes, resultP, resultC, sizeof(resultC),
|
|
iv, sizeof(iv), resultT, sizeof(resultT),
|
|
aad, sizeof(aad));
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (Decrypt: %d)\n", ret);
|
|
return ret;
|
|
}
|
|
if (memcmp(resultP, plain, sizeof(plain)) != 0) {
|
|
wolfBoot_printf("FAIL (plaintext mismatch)\n");
|
|
return -1;
|
|
}
|
|
|
|
wolfBoot_printf("PASS\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ECDHE P-256 known-answer test
|
|
* Two fixed key pairs; verify shared secret matches expected value.
|
|
* Keys from NIST ECDH test vectors (KAS_ECC_CDH_PrimitiveTest).
|
|
*/
|
|
static int test_ecdhe_p256(void)
|
|
{
|
|
ecc_key keyA, keyB;
|
|
WC_RNG rng;
|
|
int ret;
|
|
byte secretA[32], secretB[32];
|
|
word32 secretALen = sizeof(secretA);
|
|
word32 secretBLen = sizeof(secretB);
|
|
int i;
|
|
|
|
/* Party A key pair (dA, QAx, QAy) where QA = dA * G */
|
|
static const char dA[] =
|
|
"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433";
|
|
static const char QAx[] =
|
|
"dad0b65394221cf9b051e1feca5787d098dfe637fc90b9ef945d0c3772581180";
|
|
static const char QAy[] =
|
|
"5271a0461cdb8252d61f1c456fa3e59ab1f45b33accf5f58389e0577b8990bb3";
|
|
|
|
/* Party B key pair (dB, QBx, QBy) where QB = dB * G */
|
|
static const char dB[] =
|
|
"c6ef9c5d78ae012a011164acb397ce2088685d8f06bf9be0b283ab46476bee53";
|
|
static const char QBx[] =
|
|
"d12dfb5289c8d4f81208b70270398c342296970a0bccb74c736fc7554494bf63";
|
|
static const char QBy[] =
|
|
"56fbf3ca366cc23e8157854c13c58d6aac23f046ada30f8353e74f33039872ab";
|
|
|
|
/* Expected shared secret: dA * QB = dB * QA */
|
|
static const byte expSecret[] = {
|
|
0xd6, 0x84, 0x0f, 0x6b, 0x42, 0xf6, 0xed, 0xaf,
|
|
0xd1, 0x31, 0x16, 0xe0, 0xe1, 0x25, 0x65, 0x20,
|
|
0x2f, 0xef, 0x8e, 0x9e, 0xce, 0x7d, 0xce, 0x03,
|
|
0x81, 0x24, 0x64, 0xd0, 0x4b, 0x94, 0x42, 0xde,
|
|
};
|
|
|
|
wolfBoot_printf("ECDHE P-256 test: ");
|
|
|
|
/* Enable TRNG peripheral clock before wc_InitRng seeds from hardware */
|
|
GCR_PERCKCN1 &= ~GCR_PERCKCN1_TRNGD;
|
|
|
|
/* Wait for the entropy source to come up before wc_InitRng's health test */
|
|
while ((MXC_TRNG->st & MXC_F_TRNG_ST_RND_RDY) == 0) {}
|
|
|
|
ret = wc_InitRng(&rng);
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (InitRng: %d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = wc_ecc_init(&keyA);
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (init A: %d)\n", ret);
|
|
wc_FreeRng(&rng);
|
|
return ret;
|
|
}
|
|
ret = wc_ecc_init(&keyB);
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (init B: %d)\n", ret);
|
|
wc_ecc_free(&keyA);
|
|
wc_FreeRng(&rng);
|
|
return ret;
|
|
}
|
|
|
|
wc_ecc_set_rng(&keyA, &rng);
|
|
wc_ecc_set_rng(&keyB, &rng);
|
|
|
|
/* Import key A (private + public) */
|
|
ret = wc_ecc_import_raw(&keyA, QAx, QAy, dA, "SECP256R1");
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (import A: %d)\n", ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Import key B (private + public) */
|
|
ret = wc_ecc_import_raw(&keyB, QBx, QBy, dB, "SECP256R1");
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (import B: %d)\n", ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* A computes shared secret: dA * QB */
|
|
ret = wc_ecc_shared_secret(&keyA, &keyB, secretA, &secretALen);
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (shared A: %d)\n", ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* B computes shared secret: dB * QA */
|
|
ret = wc_ecc_shared_secret(&keyB, &keyA, secretB, &secretBLen);
|
|
if (ret != 0) {
|
|
wolfBoot_printf("FAIL (shared B: %d)\n", ret);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Both sides must agree */
|
|
if (secretALen != secretBLen ||
|
|
memcmp(secretA, secretB, secretALen) != 0) {
|
|
wolfBoot_printf("FAIL (secrets differ)\n");
|
|
ret = -1;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Verify against expected value */
|
|
if (secretALen != sizeof(expSecret) ||
|
|
memcmp(secretA, expSecret, sizeof(expSecret)) != 0) {
|
|
wolfBoot_printf("FAIL (expected mismatch)\n");
|
|
wolfBoot_printf(" got: ");
|
|
for (i = 0; i < (int)secretALen; i++)
|
|
wolfBoot_printf("%02x", secretA[i]);
|
|
wolfBoot_printf("\n");
|
|
ret = -1;
|
|
goto cleanup;
|
|
}
|
|
|
|
wolfBoot_printf("PASS\n");
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
wc_ecc_free(&keyB);
|
|
wc_ecc_free(&keyA);
|
|
wc_FreeRng(&rng);
|
|
return ret;
|
|
}
|
|
#endif /* WOLFCRYPT_MAX32666_TEST */
|
|
|
|
#define LED_RED_PIN (1UL << 29)
|
|
#define LED_BLUE_PIN (1UL << 30)
|
|
#define LED_GREEN_PIN (1UL << 31)
|
|
|
|
void main(void)
|
|
{
|
|
uint32_t version;
|
|
|
|
hal_init();
|
|
|
|
version = wolfBoot_current_firmware_version();
|
|
|
|
if (version == 1) {
|
|
/* Turn on blue LED */
|
|
GPIO0_EN0_SET = LED_BLUE_PIN; /* configure as GPIO */
|
|
GPIO0_OUT_EN |= LED_BLUE_PIN; /* enable output */
|
|
GPIO0_OUT_CLR = LED_BLUE_PIN; /* drive low (LED on) */
|
|
} else {
|
|
/* Turn on green LED */
|
|
GPIO0_EN0_SET = LED_GREEN_PIN; /* configure as GPIO */
|
|
GPIO0_OUT_EN |= LED_GREEN_PIN; /* enable output */
|
|
GPIO0_OUT_CLR = LED_GREEN_PIN; /* drive low (LED on) */
|
|
}
|
|
|
|
wolfBoot_printf("MAX32666 Test App v%lu\n", (unsigned long)version);
|
|
|
|
#ifdef WOLFBOOT_PERSIST_FAILURE_STATUS
|
|
{
|
|
static const char *phase_str[] = { "?", "update", "boot", "rollback",
|
|
"recovery", "self-update" };
|
|
static const char *cause_str[] = { "?", "bad header",
|
|
"hash verification failed", "signature verification failed",
|
|
"not confirmed" };
|
|
struct wolfBoot_failure_record rec;
|
|
int i, n = wolfBoot_get_failure_count();
|
|
wolfBoot_printf("Recorded failures: %d\n", n);
|
|
for (i = 0; i < n; i++) {
|
|
if (wolfBoot_get_failure(i, &rec) == 0) {
|
|
wolfBoot_printf(" [%d] %s during %s in %s partition (v%lu)\n", i,
|
|
rec.cause <= 4 ? cause_str[rec.cause] : "?",
|
|
rec.phase <= 5 ? phase_str[rec.phase] : "?",
|
|
rec.partition == PART_UPDATE ? "UPDATE" : "BOOT",
|
|
(unsigned long)rec.fw_version);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Mark boot successful to prevent rollback */
|
|
wolfBoot_success();
|
|
|
|
wolfBoot_printf("Boot success marked. Version: %lu\n",
|
|
(unsigned long)version);
|
|
|
|
#ifdef WOLFCRYPT_MAX32666_TEST
|
|
/* Initialize MAX32666 TPU hardware */
|
|
if (wc_MXC_TPU_Init() != 0) {
|
|
wolfBoot_printf("TPU init failed!\n");
|
|
} else {
|
|
wolfBoot_printf("TPU initialized.\n");
|
|
test_aes_gcm_256();
|
|
test_ecdhe_p256();
|
|
wc_MXC_TPU_Shutdown();
|
|
}
|
|
#endif
|
|
|
|
/* Main loop */
|
|
while (1) {
|
|
__asm__ volatile ("nop");
|
|
}
|
|
}
|