Skip to content
Open
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
17 changes: 13 additions & 4 deletions .github/workflows/lean-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ jobs:
uses: actions/cache@v4
with:
path: ~/wolfssl-lean
key: wolfssl-lean-ecc-v1-${{ steps.wolfssl-rev.outputs.sha }}
key: wolfssl-lean-ecc-verifyonly-v2-${{ steps.wolfssl-rev.outputs.sha }}

# Minimal backend for ES256 verification: ECC + SHA-256 only.
# No keygen and no RNG are needed to verify a COSE_Sign1.
# Verify-only ECC backend: NO_ECC_SIGN compiles ECC signing out entirely,
# mirroring an embedded verify-only target (e.g. wolfBoot). This is the
# config that catches a lean wolfCOSE accidentally pulling in a signing
# helper such as wc_ecc_sign_hash (via wolfCose_EccSignRaw): it links here
# only if the verify path references no sign-side symbols.
- name: Build minimal wolfSSL
if: steps.cache-wolfssl.outputs.cache-hit != 'true'
run: |
Expand All @@ -45,17 +48,23 @@ jobs:
cd wolfssl-lean-src
./autogen.sh
./configure --enable-cryptonly --enable-ecc \
CFLAGS="-DNO_ECC_SIGN" \
--prefix=$HOME/wolfssl-lean
make -j$(nproc)
make install

# No --gc-sections here on purpose. Against the NO_ECC_SIGN wolfSSL above, a
# verify path that leaks a signing helper (e.g. wc_ecc_sign_hash via
# wolfCose_EccSignRaw) must fail to link. With dead-code stripping the unused
# helper would be removed and the missing-symbol link error would never fire,
# so the regression would slip through unnoticed.
- name: Build and run the lean verify-only example
run: |
export WOLFSSL_DIR=$HOME/wolfssl-lean
export LD_LIBRARY_PATH=$WOLFSSL_DIR/lib
make lean-verify \
CFLAGS="-std=c11 -DHAVE_ANONYMOUS_INLINE_AGGREGATES=1 -Os -Wall -Wextra -Wpedantic -Wshadow -Wconversion -ffunction-sections -fdata-sections -I./include -isystem $WOLFSSL_DIR/include" \
LDFLAGS="-L$WOLFSSL_DIR/lib -lwolfssl -Wl,--gc-sections"
LDFLAGS="-L$WOLFSSL_DIR/lib -lwolfssl"

- name: Assert the signing API is absent from a verify-only build
run: |
Expand Down
23 changes: 21 additions & 2 deletions src/wolfcose.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ static int wolfCose_HmacCheckKeyLen(int32_t alg, size_t keyLen)
/* ----- Internal: ECC DER <-> raw r||s conversion ----- */

#ifdef WOLFCOSE_HAVE_ECDSA
#if defined(WOLFCOSE_SIGN1_SIGN) || defined(WOLFCOSE_SIGN_SIGN)
int wolfCose_EccSignRaw(const uint8_t* hash, size_t hashLen,
uint8_t* sigBuf, size_t* sigLen,
size_t coordSz, WC_RNG* rng, ecc_key* eccKey)
Expand Down Expand Up @@ -601,16 +602,20 @@ int wolfCose_EccSignRaw(const uint8_t* hash, size_t hashLen,
}
return ret;
}
#endif /* WOLFCOSE_SIGN1_SIGN || WOLFCOSE_SIGN_SIGN */

int wolfCose_EccVerifyRaw(const uint8_t* sigBuf, size_t sigLen,
const uint8_t* hash, size_t hashLen,
size_t coordSz, ecc_key* eccKey, int* verified)
{
int ret;
#ifndef NO_ASN
uint8_t derSig[ECC_MAX_SIG_SIZE];
word32 derSigLen = (word32)sizeof(derSig);
#endif

if ((sigBuf == NULL) || (hash == NULL) || (eccKey == NULL) || (verified == NULL)) {
if ((sigBuf == NULL) || (hash == NULL) || (eccKey == NULL) ||
(verified == NULL)) {
ret = WOLFCOSE_E_INVALID_ARG;
}
else if (sigLen != (coordSz * 2u)) {
Expand All @@ -619,7 +624,20 @@ int wolfCose_EccVerifyRaw(const uint8_t* sigBuf, size_t sigLen,
else {
*verified = 0;

/* Convert raw r||s to DER */
#ifdef NO_ASN
/* NO_ASN wolfCrypt (e.g. wolfBoot): wc_ecc_verify_hash consumes the raw
* r||s signature directly, so no DER conversion is needed and the
* sign-side helper wc_ecc_rs_raw_to_sig (gated on ASN) is not required.
* wolfCOSE holds no mp_int itself, keeping the verify path allocation
* free at this layer. */
INJECT_FAILURE(WOLF_FAIL_ECC_VERIFY, -1,
ret = wc_ecc_verify_hash(sigBuf, (word32)sigLen, hash,
(word32)hashLen, verified, eccKey));
if (ret != 0) {
ret = WOLFCOSE_E_CRYPTO;
}
#else
/* Convert raw r||s to DER, then verify. */
INJECT_FAILURE(WOLF_FAIL_ECC_RS_TO_SIG, -1,
ret = wc_ecc_rs_raw_to_sig(sigBuf, (word32)coordSz,
&sigBuf[coordSz], (word32)coordSz,
Expand All @@ -636,6 +654,7 @@ int wolfCose_EccVerifyRaw(const uint8_t* sigBuf, size_t sigLen,
}
}
(void)wolfCose_ForceZero(derSig, sizeof(derSig));
#endif
}
return ret;
}
Expand Down
2 changes: 2 additions & 0 deletions src/wolfcose_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,12 @@ WOLFCOSE_LOCAL int wolfCose_HmacType(int32_t alg, int* hmacType);
* \param eccKey Caller-owned ECC key with private key.
* \return WOLFCOSE_SUCCESS or negative error code.
*/
#if defined(WOLFCOSE_SIGN1_SIGN) || defined(WOLFCOSE_SIGN_SIGN)
WOLFCOSE_LOCAL int wolfCose_EccSignRaw(const uint8_t* hash, size_t hashLen,
uint8_t* sigBuf, size_t* sigLen,
size_t coordSz,
WC_RNG* rng, ecc_key* eccKey);
#endif /* WOLFCOSE_SIGN1_SIGN || WOLFCOSE_SIGN_SIGN */

/**
* \brief Verify a raw r||s ECC signature.
Expand Down
Loading