Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ tools/unit-tests/unit-mpusize
tools/unit-tests/unit-otp-keystore
tools/unit-tests/unit-otp-keystore-gen-zeroize
tools/unit-tests/unit-tpm-api-names
tools/unit-tests/unit-tpm-nsc-cert
tools/unit-tests/unit-elf-bss-guard
tools/unit-tests/unit-fit-fpga
tools/unit-tests/unit-flash-erase-c0
Expand Down
39 changes: 27 additions & 12 deletions src/arm_tee_psa_ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,8 @@ static psa_status_t wolfboot_crypto_dispatch(const psa_invec *in_vec,
return psa_generate_random((uint8_t *)out_vec[0].base, out_vec[0].len);

case ARM_TEE_CRYPTO_OPEN_KEY_SID:
if (out_vec == NULL || out_len < 1) {
if (out_vec == NULL || out_len < 1 || out_vec[0].base == NULL ||
out_vec[0].len < sizeof(psa_key_id_t)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
return wolfboot_psa_open_key(iov->key_id,
Expand All @@ -405,7 +406,9 @@ static psa_status_t wolfboot_crypto_dispatch(const psa_invec *in_vec,
return wolfboot_psa_close_key(iov->key_id);

case ARM_TEE_CRYPTO_IMPORT_KEY_SID:
if (in_len < 3 || out_vec == NULL || out_len < 1) {
if (in_len < 3 || out_vec == NULL || out_len < 1 ||
out_vec[0].base == NULL ||
out_vec[0].len < sizeof(psa_key_id_t)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (in_vec[1].base == NULL ||
Expand All @@ -425,7 +428,9 @@ static psa_status_t wolfboot_crypto_dispatch(const psa_invec *in_vec,
}

case ARM_TEE_CRYPTO_GENERATE_KEY_SID:
if (in_len < 2 || out_vec == NULL || out_len < 1) {
if (in_len < 2 || out_vec == NULL || out_len < 1 ||
out_vec[0].base == NULL ||
out_vec[0].len < sizeof(psa_key_id_t)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (in_vec[1].base == NULL ||
Expand Down Expand Up @@ -478,7 +483,8 @@ static psa_status_t wolfboot_crypto_dispatch(const psa_invec *in_vec,
}

case ARM_TEE_CRYPTO_GET_KEY_ATTRIBUTES_SID:
if (out_vec == NULL || out_len < 1) {
if (out_vec == NULL || out_len < 1 || out_vec[0].base == NULL ||
out_vec[0].len < sizeof(psa_key_attributes_t)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
return psa_get_key_attributes(iov->key_id,
Expand Down Expand Up @@ -1006,11 +1012,13 @@ static int32_t arm_tee_psa_ps_dispatch(int32_t type, const psa_invec *in_vec,
return PSA_SUCCESS;
}
if (type == ARM_TEE_PS_GET_SUPPORT) {
if (out_vec != NULL && out_len >= 1 && out_vec[0].base != NULL) {
uint32_t support = 0;
XMEMCPY(out_vec[0].base, &support, sizeof(support));
out_vec[0].len = sizeof(support);
uint32_t support = 0;
if (out_vec == NULL || out_len < 1 || out_vec[0].base == NULL ||
out_vec[0].len < sizeof(support)) {
return PSA_ERROR_INVALID_ARGUMENT;
}
XMEMCPY(out_vec[0].base, &support, sizeof(support));
out_vec[0].len = sizeof(support);
return PSA_SUCCESS;
}
return PSA_ERROR_NOT_SUPPORTED;
Expand Down Expand Up @@ -1067,13 +1075,19 @@ int32_t arm_tee_psa_call(psa_handle_t handle, int32_t type,
out_vec_s[i] = out_vec[i];
}

/* Every non-NULL .base must pass the non-secure attribution check, even
* when the declared .len is zero: a descriptor is not guaranteed to be
* accessed only within .len, so a zero-length descriptor would otherwise
* smuggle a Secure pointer past validation. At least one byte is always
* checked. */
for (i = 0; i < in_len; i++) {
if (in_vec_s[i].len > 0 && in_vec_s[i].base == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (in_vec_s[i].len > 0 &&
if (in_vec_s[i].base != NULL &&
cmse_check_address_range((void *)in_vec_s[i].base,
in_vec_s[i].len,
in_vec_s[i].len > 0 ?
in_vec_s[i].len : 1,
CMSE_NONSECURE) == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
Expand All @@ -1082,9 +1096,10 @@ int32_t arm_tee_psa_call(psa_handle_t handle, int32_t type,
if (out_vec_s[i].len > 0 && out_vec_s[i].base == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
if (out_vec_s[i].len > 0 &&
if (out_vec_s[i].base != NULL &&
cmse_check_address_range(out_vec_s[i].base,
out_vec_s[i].len,
out_vec_s[i].len > 0 ?
out_vec_s[i].len : 1,
CMSE_NONSECURE) == NULL) {
return PSA_ERROR_INVALID_ARGUMENT;
}
Expand Down
24 changes: 20 additions & 4 deletions src/pkcs11_callable.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <arm_cmse.h>
#include <stddef.h> /* offsetof */
#include <wolfssl/wolfcrypt/types.h> /* XMALLOC/XFREE/XMEMCPY, DYNAMIC_TYPE_* */
#include <wolfssl/wolfcrypt/memory.h> /* wc_ForceZero */

/*
* TrustZone-M PKCS#11 non-secure-callable (NSC) layer with pointer
Expand Down Expand Up @@ -130,6 +131,7 @@ static int ns_outlen_begin(const volatile void *pBuf, CK_ULONG_PTR pulLen,
struct nsc_mech {
CK_MECHANISM mech; /* secure mechanism passed to wolfPKCS11 */
void *alloc[NSC_MECH_MAX_ALLOC];
CK_ULONG allocLen[NSC_MECH_MAX_ALLOC];
int nAlloc;
struct {
void *dst; /* NS destination */
Expand All @@ -148,8 +150,10 @@ static void *nsc_alloc(struct nsc_mech *m, CK_ULONG len)
if (m->nAlloc >= NSC_MECH_MAX_ALLOC)
return NULL;
p = XMALLOC((size_t)len, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (p != NULL)
if (p != NULL) {
m->allocLen[m->nAlloc] = len;
m->alloc[m->nAlloc++] = p;
}
return p;
}

Expand Down Expand Up @@ -205,13 +209,17 @@ static CK_RV nsc_inout(struct nsc_mech *m, CK_VOID_PTR dst, CK_ULONG len,
return CKR_OK;
}

/* Free all secure allocations without copying anything back (error path). */
/* Free all secure allocations without copying anything back (error path).
* Parameter blobs can carry secrets (CKM_PKCS5_PBKD2 pPassword, HKDF salt,
* ...), so scrub every block before it goes back to the secure heap. */
static void nsc_mech_free(struct nsc_mech *m)
{
int i;

for (i = 0; i < m->nAlloc; i++)
for (i = 0; i < m->nAlloc; i++) {
wc_ForceZero(m->alloc[i], (size_t)m->allocLen[i]);
XFREE(m->alloc[i], NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
m->nAlloc = 0;
m->nCback = 0;
}
Expand Down Expand Up @@ -551,8 +559,16 @@ static void nsc_tmpl_free(struct nsc_tmpl *t)

if (t->work != NULL) {
for (i = 0; i < t->count; i++) {
if (t->work[i].pValue != NULL)
if (t->work[i].pValue != NULL) {
/* Value buffers hold imported key material (CKA_VALUE, the RSA
* private components, ...). Scrub before releasing, using the
* snapshot length: that is what was allocated, and wolfPKCS11
* rewrites work[].ulValueLen on the C_GetAttributeValue path. */
if (t->snap != NULL)
wc_ForceZero(t->work[i].pValue,
(size_t)t->snap[i].ulValueLen);
XFREE(t->work[i].pValue, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
XFREE(t->work, NULL, DYNAMIC_TYPE_TMP_BUFFER);
t->work = NULL;
Expand Down
17 changes: 15 additions & 2 deletions src/tpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1334,14 +1334,27 @@ int CSME_NSE_API wolfBoot_tpm2_read_pcr(uint8_t pcrIndex, uint8_t* digest, int*

int CSME_NSE_API wolfBoot_tpm2_read_cert(uint32_t handle, uint8_t* cert, uint32_t* certSz)
{
uint32_t certCapacity;
int rc;

if (WOLFBOOT_TPM_NS_RW(certSz, sizeof(*certSz)) == NULL) {
return BAD_FUNC_ARG;
}
if (WOLFBOOT_TPM_NS_RW(cert, *certSz) == NULL) {
/* single-fetch *certSz so it cannot be re-read after validation: wolfTPM
* checks the capacity again before filling 'cert', and a racing non-secure
* agent would otherwise enlarge it in between to reopen the write past the
* range validated here */
certCapacity = *(volatile const uint32_t*)certSz;
if (certCapacity == 0) {
return BAD_FUNC_ARG;
}
if (WOLFBOOT_TPM_NS_RW(cert, certCapacity) == NULL) {
return BAD_FUNC_ARG;
}
wolfTPM2_SetAuthPassword(&wolftpm_dev, 0, NULL);
return wolfTPM2_NVReadCert(&wolftpm_dev, handle, cert, certSz);
rc = wolfTPM2_NVReadCert(&wolftpm_dev, handle, cert, &certCapacity);
*certSz = certCapacity;
return rc;
}

#ifdef WOLFTPM_MFG_IDENTITY
Expand Down
32 changes: 24 additions & 8 deletions tools/keytools/sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,8 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,

/* open and load key buffer */
*key_buffer = NULL;
*pubkey = NULL;
*pubkey_sz = 0;
if (secondary) {
key_file = CMD.secondary_key_file;
sign = CMD.secondary_sign;
Expand Down Expand Up @@ -722,8 +724,10 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
wc_ed25519_free(&key.ed);
}

if (ret != 0)
if (ret != 0) {
free(*pubkey);
*pubkey = NULL;
}

/* break if we succeed or are not using auto */
if (ret == 0 || sign != SIGN_AUTO) {
Expand Down Expand Up @@ -789,8 +793,10 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
wc_ed448_free(&key.ed4);
}

if (ret != 0)
if (ret != 0) {
free(*pubkey);
*pubkey = NULL;
}

/* break if we succeed or are not using auto */
if (ret == 0 || sign != SIGN_AUTO) {
Expand Down Expand Up @@ -1051,6 +1057,11 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
zero_and_free(*key_buffer, *key_buffer_sz);
*key_buffer = NULL;
}
if (*pubkey != NULL) {
free(*pubkey);
*pubkey = NULL;
}
*pubkey_sz = 0;
return NULL;
}

Expand Down Expand Up @@ -3728,12 +3739,15 @@ int main(int argc, char** argv)
if (CMD.hybrid) {
uint8_t *kbuf2 = NULL;
uint8_t *pubkey2 = NULL;
uint32_t pubkey_sz2;
uint32_t pubkey_sz2 = 0;
DEBUG_PRINT("Loading secondary key\n");
kbuf2 = load_key(&key_buffer2, &key_buffer_sz2, &pubkey2, &pubkey_sz2, 1);
if (!kbuf2) {
exit(1);
}
printf("Creating hybrid signature\n");
make_hybrid_header(pubkey, pubkey_sz, CMD.image_file, CMD.output_image_file,
pubkey2, pubkey_sz2);
ret = make_hybrid_header(pubkey, pubkey_sz, CMD.image_file,
CMD.output_image_file, pubkey2, pubkey_sz2);
DEBUG_PRINT("Signature size: %u\n", CMD.signature_sz);
DEBUG_PRINT("Secondary signature size: %u\n", CMD.secondary_signature_sz);
DEBUG_PRINT("Header size: %u\n", CMD.header_sz);
Expand All @@ -3742,11 +3756,13 @@ int main(int argc, char** argv)
if (pubkey2)
free(pubkey2);
} else {
make_header(pubkey, pubkey_sz, CMD.image_file, CMD.output_image_file);
ret = make_header(pubkey, pubkey_sz, CMD.image_file,
CMD.output_image_file);
}


if (CMD.delta) {
/* Skip the delta step and propagate the failure to the caller if the
* signed image could not be created. */
if ((ret == 0) && CMD.delta) {
if (CMD.encrypt)
ret = base_diff(CMD.delta_base_file, pubkey, pubkey_sz, 64);
else
Expand Down
37 changes: 37 additions & 0 deletions tools/unit-tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,13 @@ TESTS:=unit-parser unit-fdt unit-extflash unit-string unit-spi-flash unit-aes128
unit-image-nopart unit-image-sha384 unit-image-sha3-384 unit-store-sbrk \
unit-tpm-blob unit-policy-create unit-policy-sign unit-rot-auth unit-sdhci-response-bits \
unit-sdhci-disk-unaligned unit-sign-encrypted-output \
unit-sign-hybrid-keyload \
unit-sign-header-failure \
unit-keygen-xmss-params
TESTS+=unit-tpm-check-rot-auth
TESTS+=unit-tpm-api-names
TESTS+=unit-tpm-nsc-cert
TESTS+=unit-pkcs11-nsc-zeroize
TESTS+=unit-diagnostics
TESTS+=unit-diagnostics-256
TESTS+=unit-fit-gzip unit-fit-nogzip
Expand Down Expand Up @@ -280,6 +284,23 @@ unit-tpm-api-names: ../../include/target.h unit-tpm-api-names.c ../../src/string
-DWOLFBOOT_HASH_SHA256 \
-ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections

unit-tpm-nsc-cert: ../../include/target.h unit-tpm-nsc-cert.c ../../src/string.c
gcc -o $@ $^ $(CFLAGS) -I$(WOLFBOOT_LIB_WOLFTPM) -DWOLFBOOT_TPM \
-DWOLFTPM_USER_SETTINGS -DWOLFBOOT_SIGN_RSA2048 \
-DWOLFBOOT_HASH_SHA256 -D__ARM_FEATURE_CMSE=3U -DCSME_NSE_API= \
-ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections

# The PKCS#11 NSC veneers are exercised here through C_CreateObject_nsc_call
# and C_DeriveKey_nsc_call only; --gc-sections drops the remaining veneers so
# just those two wolfPKCS11 entry points need a stub.
unit-pkcs11-nsc-zeroize: ../../include/target.h unit-pkcs11-nsc-zeroize.c
gcc -o $@ unit-pkcs11-nsc-zeroize.c \
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/memory.c \
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/misc.c \
$(CFLAGS) -I$(WOLFBOOT_LIB_WOLFPKCS11) -DSECURE_PKCS11 \
-DWOLFPKCS11_USER_SETTINGS -DWOLFCRYPT_SECURE_MODE \
-ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections

unit-fwtpm-stub: ../../include/target.h unit-fwtpm-stub.c
gcc -o $@ $^ $(CFLAGS) -I$(WOLFBOOT_LIB_WOLFTPM) \
-DWOLFTPM_USER_SETTINGS -ffunction-sections -fdata-sections \
Expand Down Expand Up @@ -316,6 +337,22 @@ unit-sign-encrypted-output: ../../include/target.h unit-sign-encrypted-output.c
-ffunction-sections -fdata-sections \
$(LDFLAGS) -Wl,--gc-sections

unit-sign-hybrid-keyload: ../../include/target.h unit-sign-hybrid-keyload.c \
$(KEYTOOLS_SIGN_SRCS)
gcc -o $@ $^ -I../keytools $(CFLAGS) -DML_DSA_LEVEL=2 -DDELTA_UPDATES \
-D"LMS_LEVELS=1" -D"LMS_HEIGHT=10" -D"LMS_WINTERNITZ=8" \
-DWOLFBOOT_XMSS_PARAMS=\"XMSS-SHA2_10_256\" \
-ffunction-sections -fdata-sections \
$(LDFLAGS) -Wl,--gc-sections

unit-sign-header-failure: ../../include/target.h unit-sign-header-failure.c \
$(KEYTOOLS_SIGN_SRCS)
gcc -o $@ $^ -I../keytools $(CFLAGS) -DML_DSA_LEVEL=2 -DDELTA_UPDATES \
-D"LMS_LEVELS=1" -D"LMS_HEIGHT=10" -D"LMS_WINTERNITZ=8" \
-DWOLFBOOT_XMSS_PARAMS=\"XMSS-SHA2_10_256\" \
-ffunction-sections -fdata-sections \
$(LDFLAGS) -Wl,--gc-sections

unit-keygen-xmss-params: ../../include/target.h unit-keygen-xmss-params.c
gcc -o $@ $^ -I../keytools $(CFLAGS) -DML_DSA_LEVEL=2 \
-D"LMS_LEVELS=1" -D"LMS_HEIGHT=10" -D"LMS_WINTERNITZ=8" \
Expand Down
7 changes: 5 additions & 2 deletions tools/unit-tests/arm_cmse.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#ifndef UNIT_TEST_ARM_CMSE_H
#define UNIT_TEST_ARM_CMSE_H

#include <stddef.h>
#include <stdint.h>

#define CMSE_NONSECURE 0
#define cmse_check_address_range(ptr, size, flags) \
((void *)(uintptr_t)(ptr))

/* Provided by the unit test, so it can model a Secure region that must never
* pass a non-secure attribution check. */
void *cmse_check_address_range(void *ptr, size_t size, int flags);

#endif
Loading
Loading