Skip to content

Navigation Menu

Sign in
Sign up

Add RFC 9783 PSA/EAT Support #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
aidangarske wants to merge 6 commits into wolfSSL:main
base: main
Choose a base branch
Loading
from aidangarske:eat-psa-rfc9783
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Fix PSA EAT CI failures
  • Loading branch information
aidangarske committed Sep 3, 2026
commit 2e4fd0c1bdde6c9f0fa44980e6402f80a30e5478
34 changes: 17 additions & 17 deletions Makefile
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ EAT_PSA_LIMITS_TEST_BIN = tests/test_wolfcose_eat_psa_limits

# Full PSA/EAT conformance test profile. Production integrations can select a
# smaller subset by defining only the WOLFCOSE_ENABLE_EAT_PSA_* switches they
# need; see docs/PSA-EAT.md. This variable is overrideable for CI experiments.
# need; see docs/PSA-EAT.md. This variable is overridable for CI experiments.
EAT_PSA_FULL_FLAGS ?= -DWOLFCOSE_ENABLE_EAT_PSA \
-DWOLFCOSE_ENABLE_EAT_PSA_CURRENT \
-DWOLFCOSE_ENABLE_EAT_PSA_SIGN1 -DWOLFCOSE_ENABLE_EAT_PSA_MAC0 \
Expand Down Expand Up @@ -288,16 +288,16 @@ ecdsa-policy-test:
rsapss-policy-test:
$(CC) $(CFLAGS) -Werror=unused-function -fsyntax-only \
-DWOLFCOSE_NO_SIGN1 -DWOLFCOSE_NO_SIGN src/wolfcose.c
$(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H \
$(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H -DWC_NO_HARDEN \
-DWC_RSA_PSS -DWOLFCOSE_NO_KEY_ENCODE \
-DWOLFCOSE_ENABLE_RSAPSS src/wolfcose.c
$(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H \
$(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H -DWC_NO_HARDEN \
-DWC_RSA_PSS -DWOLFCOSE_LEAN_VERIFY \
-DWOLFCOSE_ENABLE_RSAPSS src/wolfcose.c
@set -e; \
log_file=$$(mktemp "$${TMPDIR:-/tmp}/wolfcose-rsapss.XXXXXX"); \
trap 'rm -f "$$log_file"' 0 1 2 3 15; \
if $(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H \
if $(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H -DWC_NO_HARDEN \
-UHAVE_ECC -UWOLFSSL_EXPORT_INT \
-DWC_RSA_PSS -DWOLFCOSE_ENABLE_RSAPSS \
-DWOLFSSL_RSA_VERIFY_ONLY -DWOLFCOSE_LEAN_VERIFY \
Expand All @@ -307,7 +307,7 @@ rsapss-policy-test:
fi; \
grep -q "RSA-PSS key validation requires WOLFSSL_EXPORT_INT" \
"$$log_file"
$(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H \
$(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H -DWC_NO_HARDEN \
-UHAVE_ECC -UWOLFSSL_EXPORT_INT \
-DWC_RSA_PSS -DWOLFCOSE_ENABLE_RSAPSS \
-DWOLFSSL_RSA_VERIFY_ONLY -DWOLFSSL_EXPORT_INT \
Expand All @@ -316,7 +316,7 @@ rsapss-policy-test:
log_file=$$(mktemp "$${TMPDIR:-/tmp}/wolfcose-rsapss.XXXXXX"); \
trap 'rm -f "$$log_file"' 0 1 2 3 15; \
for backend in WOLF_CRYPTO_CB WOLFSSL_MICROCHIP_TA100; do \
if $(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H \
if $(CC) $(CFLAGS) -x c -fsyntax-only -DWOLFSSL_NO_OPTIONS_H -DWC_NO_HARDEN \
-UHAVE_ECC -UWOLFSSL_EXPORT_INT \
-DWC_RSA_PSS -DWOLFCOSE_ENABLE_RSAPSS \
-DWOLFSSL_RSA_VERIFY_ONLY -D$$backend \
Expand Down Expand Up @@ -423,7 +423,7 @@ eat-psa-profile-test:
eat-psa-config-check:
$(MAKE) clean
$(MAKE) all
@if nm $(LIB_A) | grep -q "wc_CoseEatPsaToken_"; then \
@if nm $(LIB_A) | grep "wc_CoseEatPsaToken_" >/dev/null; then \
echo "FAIL: default library exports PSA/EAT"; exit 1; \
fi
@echo "PASS: default library has no PSA/EAT symbols"
Expand All @@ -432,48 +432,48 @@ eat-psa-config-check:
$(MAKE) test EXTRA_CFLAGS='-DWOLFCOSE_ENABLE_COSE_TEXT_LABELS'
@echo "PASS: generic COSE text-label extension is independently selectable"
$(MAKE) all EXTRA_CFLAGS='$(EAT_PSA_FULL_FLAGS)'
@if ! nm $(LIB_A) | grep -q "wc_CoseEatPsaToken_Verify"; then \
@if ! nm $(LIB_A) | grep "wc_CoseEatPsaToken_Verify" >/dev/null; then \
echo "FAIL: enabled library omits PSA/EAT verifier"; exit 1; \
fi
$(MAKE) all
@if nm $(LIB_A) | grep -q "wc_CoseEatPsaToken_"; then \
@if nm $(LIB_A) | grep "wc_CoseEatPsaToken_" >/dev/null; then \
echo "FAIL: enabled-to-default build retained PSA/EAT symbols"; exit 1; \
fi
$(MAKE) all EXTRA_CFLAGS='-DHAVE_CONFIG_H -I./tests/config/eat_psa_config'
@if ! nm $(LIB_A) | grep -q "wc_CoseEatPsaToken_Verify"; then \
@if ! nm $(LIB_A) | grep "wc_CoseEatPsaToken_Verify" >/dev/null; then \
echo "FAIL: config.h-enabled library omits PSA/EAT verifier"; exit 1; \
fi
$(MAKE) all
@if nm $(LIB_A) | grep -q "wc_CoseEatPsaToken_"; then \
@if nm $(LIB_A) | grep "wc_CoseEatPsaToken_" >/dev/null; then \
echo "FAIL: config.h-to-default build retained PSA/EAT symbols"; exit 1; \
fi
$(MAKE) all EXTRA_CFLAGS='-DWOLFCOSE_LEAN $(EAT_PSA_NO_DECODE_FLAGS) \
-DWOLFCOSE_ENABLE_EAT_PSA -DWOLFCOSE_ENABLE_EAT_PSA_CURRENT \
-DWOLFCOSE_ENABLE_EAT_PSA_ISSUE'
@if ! nm $(LIB_A) | grep -q "wc_CoseEatPsaToken_EncodeClaims"; then \
@if ! nm $(LIB_A) | grep "wc_CoseEatPsaToken_EncodeClaims" >/dev/null; then \
echo "FAIL: claim-only issuer omits claim encoder"; exit 1; \
fi
@if nm $(LIB_A) | grep -E -q "wc_CoseEatPsaToken_(Verify|Create)"; then \
@if nm $(LIB_A) | grep -E "wc_CoseEatPsaToken_(Verify|Create)" >/dev/null; then \
echo "FAIL: claim-only issuer contains a verifier or envelope creator"; exit 1; \
fi
$(MAKE) all EXTRA_CFLAGS='-DWOLFCOSE_LEAN $(EAT_PSA_NO_DECODE_FLAGS) \
-DWOLFCOSE_ENABLE_EAT_PSA -DWOLFCOSE_ENABLE_EAT_PSA_CURRENT \
-DWOLFCOSE_ENABLE_EAT_PSA_ISSUE \
-DWOLFCOSE_ENABLE_EAT_PSA_SIGN1_ISSUE'
@if ! nm $(LIB_A) | grep -q "wc_CoseEatPsaToken_CreateSign1"; then \
@if ! nm $(LIB_A) | grep "wc_CoseEatPsaToken_CreateSign1" >/dev/null; then \
echo "FAIL: Sign1-only issuer omits Sign1 creator"; exit 1; \
fi
@if nm $(LIB_A) | grep -E -q "wc_CoseEatPsaToken_(Verify|CreateMac0)"; then \
@if nm $(LIB_A) | grep -E "wc_CoseEatPsaToken_(Verify|CreateMac0)" >/dev/null; then \
echo "FAIL: Sign1-only issuer contains verifier or Mac0 creator"; exit 1; \
fi
$(MAKE) all EXTRA_CFLAGS='-DWOLFCOSE_LEAN $(EAT_PSA_NO_DECODE_FLAGS) \
-DWOLFCOSE_ENABLE_EAT_PSA -DWOLFCOSE_ENABLE_EAT_PSA_CURRENT \
-DWOLFCOSE_ENABLE_EAT_PSA_ISSUE \
-DWOLFCOSE_ENABLE_EAT_PSA_MAC0_ISSUE'
@if ! nm $(LIB_A) | grep -q "wc_CoseEatPsaToken_CreateMac0"; then \
@if ! nm $(LIB_A) | grep "wc_CoseEatPsaToken_CreateMac0" >/dev/null; then \
echo "FAIL: Mac0-only issuer omits Mac0 creator"; exit 1; \
fi
@if nm $(LIB_A) | grep -E -q "wc_CoseEatPsaToken_(Verify|CreateSign1)"; then \
@if nm $(LIB_A) | grep -E "wc_CoseEatPsaToken_(Verify|CreateSign1)" >/dev/null; then \
echo "FAIL: Mac0-only issuer contains verifier or Sign1 creator"; exit 1; \
fi
$(MAKE) all
Expand Down
2 changes: 1 addition & 1 deletion include/wolfcose/eat_psa.h
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ extern "C" {
#ifdef WOLFCOSE_EAT_PSA

#define WOLFCOSE_EAT_PSA_PROFILE_TFM \
"tag:psacertified.org,2023:psa#tfm"
"tag:psacertified.org,2023:psa\x23" "tfm"
#define WOLFCOSE_EAT_PSA_PROFILE_LEGACY "PSA_IOT_PROFILE_1"

/* PSA/EAT-specific errors are intentionally absent from the base API when
Expand Down
6 changes: 3 additions & 3 deletions include/wolfcose/settings.h
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,9 @@ extern "C" {

/* ES256 — core. ECC_USER_CURVES keeps P-256 unless NO_ECC256 selects it
* out; HAVE_ALL_CURVES is the equivalent all-curves configuration. */
#if defined(HAVE_ECC) && !defined(NO_SHA256) && !defined(NO_ECC256) && \
(!defined(ECC_MIN_KEY_SZ) || (ECC_MIN_KEY_SZ <= 256)) && \
!defined(WOLFCOSE_NO_ES256)
#if !defined(WOLFCOSE_NO_ES256) && defined(HAVE_ECC) && \
!defined(NO_SHA256) && !defined(NO_ECC256) && \
(!defined(ECC_MIN_KEY_SZ) || (ECC_MIN_KEY_SZ <= 256))
#define WOLFCOSE_HAVE_ES256
#endif

Expand Down
11 changes: 11 additions & 0 deletions scripts/misra-deviations.json
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@
],
"expected": 1
},
{
"id": "D-11.4-001",
"rule": "11.4",
"path": "src/wolfcose_eat_psa.c",
"symbol": "wolfCose_EatPsaBuffersOverlap",
"anchors": [
" uintptr_t aStart = (uintptr_t)a;",
" uintptr_t bStart = (uintptr_t)b;"
],
"expected": 2
},
{
"id": "D-19.2-001",
"rule": "19.2",
Expand Down
4 changes: 3 additions & 1 deletion src/wolfcose_cbor.c
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ static int wolfCose_CBOR_IsUtf8(const uint8_t* data, size_t len)
ret = 0;
}
while ((i < len) && (ret != 0)) {
uint8_t first = data[i++];
uint8_t first = data[i];

i++;

if (first <= 0x7Fu) {
/* Single-byte ASCII code point. */
Expand Down
93 changes: 68 additions & 25 deletions src/wolfcose_eat_psa.c
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,6 @@
(defined(WOLFCOSE_EAT_PSA_TFM_FULL) || defined(WOLFCOSE_EAT_PSA_ISSUE))
static const uint8_t kEatPsaTfmProfile[] = WOLFCOSE_EAT_PSA_PROFILE_TFM;
#endif
#if defined(WOLFCOSE_EAT_PSA_LEGACY)
static const uint8_t kEatPsaLegacyProfile[] = WOLFCOSE_EAT_PSA_PROFILE_LEGACY;
#endif

/* RFC 9783 Section 5.1 allows CBOR variation serialization. Keep that
* tolerance scoped to authenticated PSA/EAT parsing; the public CBOR API
* remains strict and carries no profile-specific decode state. */
Expand Down Expand Up @@ -122,21 +118,43 @@ static const uint8_t kEatPsaLegacyProfile[] = WOLFCOSE_EAT_PSA_PROFILE_LEGACY;
#define WOLFCOSE_EAT_PSA_SKIP(ctx) \
wolfCose_CBOR_Skip_ex((ctx), WOLFCOSE_EAT_PSA_DECODE_FLAGS)

#if defined(WOLFCOSE_EAT_PSA_VERIFY)
static int wolfCose_EatPsaConstantCompare(const uint8_t* a, const uint8_t* b,
size_t length)
{
size_t i;
volatile unsigned int result = 0u;

for (i = 0u; i < length; i++) {
result |= (unsigned int)a[i] ^ (unsigned int)b[i];
}

return (int)result;
}
#endif

#if defined(WOLFCOSE_EAT_PSA_ISSUE)
static int wolfCose_EatPsaBuffersOverlap(const uint8_t* a, size_t aSz,
const uint8_t* b, size_t bSz)
{
int overlap = 0;

if ((a != NULL) && (b != NULL) && (aSz != 0u) && (bSz != 0u)) {
uintptr_t aStart = (uintptr_t)(const void*)a;
uintptr_t bStart = (uintptr_t)(const void*)b;

if (aStart <= bStart) {
overlap = ((bStart - aStart) < (uintptr_t)aSz) ? 1 : 0;
/* uintptr_t is used intentionally: relational comparison of pointers
* to unrelated caller-owned objects is not defined by ISO C. */
uintptr_t aStart = (uintptr_t)a;
uintptr_t bStart = (uintptr_t)b;

if ((aStart <= bStart) &&
((bStart - aStart) < (uintptr_t)aSz)) {
overlap = 1;
}
else if ((aStart > bStart) &&
((aStart - bStart) < (uintptr_t)bSz)) {
overlap = 1;
}
else {
overlap = ((aStart - bStart) < (uintptr_t)bSz) ? 1 : 0;
/* The nonempty buffer ranges are disjoint. */
}
}

Expand All @@ -159,9 +177,9 @@ static int wolfCose_EatPsaComponentOverlapsBuffer(
int overlap = 0;

if (component != NULL) {
overlap =
overlap = (
(wolfCose_EatPsaBuffersOverlap(
(const uint8_t*)(const void*)component, sizeof(*component),
(const uint8_t*)component, sizeof(*component),
buffer, bufferSz) != 0) ||
(wolfCose_EatPsaSpanOverlapsBuffer(&component->measurementType,
buffer, bufferSz) != 0) ||
Expand All @@ -172,7 +190,7 @@ static int wolfCose_EatPsaComponentOverlapsBuffer(
(wolfCose_EatPsaSpanOverlapsBuffer(&component->signerId,
buffer, bufferSz) != 0) ||
(wolfCose_EatPsaSpanOverlapsBuffer(&component->measurementDesc,
buffer, bufferSz) != 0);
buffer, bufferSz) != 0)) ? 1 : 0;
}

return overlap;
Expand All @@ -190,9 +208,9 @@ static int wolfCose_EatPsaClaimsOverlapBuffer(
if (claims != NULL) {
size_t i;

overlap =
overlap = (
(wolfCose_EatPsaBuffersOverlap(
(const uint8_t*)(const void*)claims, sizeof(*claims),
(const uint8_t*)claims, sizeof(*claims),
buffer, bufferSz) != 0) ||
(wolfCose_EatPsaSpanOverlapsBuffer(&claims->nonce,
buffer, bufferSz) != 0) ||
Expand All @@ -206,7 +224,7 @@ static int wolfCose_EatPsaClaimsOverlapBuffer(
&claims->certificationReference, buffer, bufferSz) != 0) ||
(wolfCose_EatPsaSpanOverlapsBuffer(
&claims->verificationServiceIndicator, buffer,
bufferSz) != 0);
bufferSz) != 0)) ? 1 : 0;
for (i = 0u; (overlap == 0) && (i < claims->componentCount); i++) {
overlap = wolfCose_EatPsaComponentOverlapsBuffer(
&claims->components[i], buffer, bufferSz);
Expand Down Expand Up @@ -250,9 +268,10 @@ static int wolfCose_EatPsaIsOptionalSpan(const WOLFCOSE_EAT_PSA_SPAN* span)
{
int ret = 0;

if (span != NULL) {
ret = (((span->data == NULL) && (span->len == 0u)) ||
(span->data != NULL)) ? 1 : 0;
if ((span != NULL) &&
(((span->data == NULL) && (span->len == 0u)) ||
(span->data != NULL))) {
ret = 1;
}

return ret;
Expand Down Expand Up @@ -291,6 +310,9 @@ static int wolfCose_EatPsaCertRefValid(const WOLFCOSE_EAT_PSA_SPAN* span,
(span->data[i] > (uint8_t)'9')) {
ret = 0;
}
else {
/* The character is a valid decimal digit. */
}
}
}

Expand Down Expand Up @@ -751,6 +773,9 @@ static int wolfCose_EatPsaDecodeComponent(WOLFCOSE_CBOR_CTX* ctx,
else if (ret == WOLFCOSE_SUCCESS) {
ret = WOLFCOSE_EAT_PSA_SKIP(ctx);
}
else {
/* Preserve the error produced while decoding the component. */
}
}
if ((ret == WOLFCOSE_SUCCESS) &&
((wolfCose_EatPsaIsHash(&component->measurementValue) == 0) ||
Expand All @@ -767,14 +792,16 @@ static int wolfCose_EatPsaDecodeComponents(WOLFCOSE_CBOR_CTX* ctx,
int ret;
size_t i;
size_t count = 0u;
size_t startIdx = 0u;
const uint8_t* start;
WOLFCOSE_EAT_PSA_COMPONENT component;

if ((ctx == NULL) || (token == NULL) || (ctx->idx >= ctx->bufSz)) {
ret = WOLFCOSE_E_INVALID_ARG;
}
else {
start = &ctx->cbuf[ctx->idx];
startIdx = ctx->idx;
start = &ctx->cbuf[startIdx];
ret = WOLFCOSE_EAT_PSA_DECODE_ARRAY(ctx, &count);
}
if ((ret == WOLFCOSE_SUCCESS) &&
Expand All @@ -786,7 +813,7 @@ static int wolfCose_EatPsaDecodeComponents(WOLFCOSE_CBOR_CTX* ctx,
}
if (ret == WOLFCOSE_SUCCESS) {
token->components.data = start;
token->components.len = (size_t)(&ctx->cbuf[ctx->idx] - start);
token->components.len = ctx->idx - startIdx;
token->componentCount = count;
}

Expand Down Expand Up @@ -814,8 +841,11 @@ static int wolfCose_EatPsaSetProfile(WOLFCOSE_EAT_PSA_TOKEN* token,
}
else if (profile == WOLFCOSE_EAT_PSA_PROFILE_OLD) {
#if defined(WOLFCOSE_EAT_PSA_LEGACY)
expected = kEatPsaLegacyProfile;
expectedLen = sizeof(kEatPsaLegacyProfile) - 1u;
static const uint8_t legacyProfile[] =
WOLFCOSE_EAT_PSA_PROFILE_LEGACY;

expected = legacyProfile;
expectedLen = sizeof(legacyProfile) - 1u;
#else
ret = WOLFCOSE_E_EAT_PSA_PROFILE;
#endif
Expand All @@ -825,7 +855,7 @@ static int wolfCose_EatPsaSetProfile(WOLFCOSE_EAT_PSA_TOKEN* token,
}
if (ret == WOLFCOSE_SUCCESS) {
if ((textLen != expectedLen) ||
(XMEMCMP(text, expected, textLen) != 0)) {
(wolfCose_EatPsaConstantCompare(text, expected, textLen) != 0)) {
ret = WOLFCOSE_E_EAT_PSA_PROFILE;
}
else {
Expand Down Expand Up @@ -1113,6 +1143,9 @@ static int wolfCose_EatPsaDecodeClaims(const uint8_t* payload,
}
}
}
else {
/* Preserve the error produced while decoding the map label. */
}
}
if ((ret == WOLFCOSE_SUCCESS) && (ctx.idx != ctx.bufSz)) {
ret = WOLFCOSE_E_EAT_PSA_CLAIM;
Expand All @@ -1130,6 +1163,9 @@ static int wolfCose_EatPsaDecodeClaims(const uint8_t* payload,
else if (token->profile != WOLFCOSE_EAT_PSA_PROFILE_CURRENT) {
ret = WOLFCOSE_E_EAT_PSA_PROFILE;
}
else {
/* All required current-profile claims were decoded. */
}
}
#endif
#if defined(WOLFCOSE_EAT_PSA_LEGACY)
Expand All @@ -1148,6 +1184,9 @@ static int wolfCose_EatPsaDecodeClaims(const uint8_t* payload,
else if (token->profile != WOLFCOSE_EAT_PSA_PROFILE_OLD) {
ret = WOLFCOSE_E_EAT_PSA_PROFILE;
}
else {
/* All required legacy-profile claims were decoded. */
}
}
#endif
if ((ret == WOLFCOSE_SUCCESS) &&
Expand Down Expand Up @@ -1288,9 +1327,13 @@ static int wolfCose_EatPsaCheckNonce(const WOLFCOSE_EAT_PSA_TOKEN* token,
ret = WOLFCOSE_E_INVALID_ARG;
}
else if ((token->nonce.len != expectedNonceLen) ||
(XMEMCMP(token->nonce.data, expectedNonce, expectedNonceLen) != 0)) {
(wolfCose_EatPsaConstantCompare(token->nonce.data, expectedNonce,
expectedNonceLen) != 0)) {
ret = WOLFCOSE_E_EAT_PSA_NONCE;
}
else {
/* The authenticated nonce matches the caller's challenge. */
}

return ret;
}
Expand Down
Loading
Loading

AltStyle によって変換されたページ (->オリジナル) /