diff --git a/include/wolfcose/settings.h b/include/wolfcose/settings.h index 343230b..7b39205 100644 --- a/include/wolfcose/settings.h +++ b/include/wolfcose/settings.h @@ -472,6 +472,14 @@ extern "C" { #error "wolfCOSE RSA-PSS key validation requires WOLFSSL_EXPORT_INT" #endif +/* The local ECDSA signing path converts a wolfCrypt DER signature to the + * fixed-width COSE representation. NO_ASN is supported for verification + * builds only. */ +#if defined(NO_ASN) && defined(WOLFCOSE_HAVE_ECDSA) && \ + (defined(WOLFCOSE_SIGN1_SIGN) || defined(WOLFCOSE_SIGN_SIGN)) + #error "wolfCOSE ECDSA signing requires ASN support" +#endif + /* Optional RFC 6979 deterministic ECDSA signing. */ #if defined(WOLFCOSE_ENABLE_DETERMINISTIC_ECDSA) && \ defined(WOLFCOSE_HAVE_ECDSA) && \ diff --git a/src/wolfcose_encrypt.c b/src/wolfcose_encrypt.c index dc85ef0..189eadf 100644 --- a/src/wolfcose_encrypt.c +++ b/src/wolfcose_encrypt.c @@ -152,6 +152,10 @@ int wc_CoseEncrypt_Encrypt(const WOLFCOSE_RECIPIENT* recipients, (iv == NULL) || (ivLen == 0u)) { ret = WOLFCOSE_E_INVALID_ARG; } + if ((ret == WOLFCOSE_SUCCESS) && (detachedPayload == NULL) && + (detachedLen != 0u)) { + ret = WOLFCOSE_E_INVALID_ARG; + } #ifdef WOLFCOSE_CHECK_WORD32_LEN if ((ret == WOLFCOSE_SUCCESS) && @@ -649,6 +653,7 @@ int wc_CoseEncrypt_Encrypt(const WOLFCOSE_RECIPIENT* recipients, #if defined(WOLFCOSE_HAVE_AESGCM) || defined(WOLFCOSE_HAVE_AESCCM) if (aesInited != 0) { (void)wc_AesFree(&aes); + (void)wolfCose_ForceZero(&aes, sizeof(aes)); } #endif #if defined(WOLFCOSE_KEY_WRAP) @@ -1263,6 +1268,7 @@ int wc_CoseEncrypt_Decrypt(const WOLFCOSE_RECIPIENT* recipient, #if defined(WOLFCOSE_HAVE_AESGCM) || defined(WOLFCOSE_HAVE_AESCCM) if (aesInited != 0) { (void)wc_AesFree(&aes); + (void)wolfCose_ForceZero(&aes, sizeof(aes)); } #endif #if defined(WOLFCOSE_KEY_WRAP) diff --git a/src/wolfcose_encrypt0.c b/src/wolfcose_encrypt0.c index dd44067..f275c1e 100644 --- a/src/wolfcose_encrypt0.c +++ b/src/wolfcose_encrypt0.c @@ -416,6 +416,7 @@ int wc_CoseEncrypt0_Encrypt(const WOLFCOSE_KEY* key, int32_t alg, #if defined(WOLFCOSE_HAVE_AESGCM) || defined(WOLFCOSE_HAVE_AESCCM) if (aesInited != 0) { (void)wc_AesFree(&aes); + (void)wolfCose_ForceZero(&aes, sizeof(aes)); } #endif if (scratch != NULL) { @@ -726,6 +727,7 @@ int wc_CoseEncrypt0_Decrypt(const WOLFCOSE_KEY* key, #if defined(WOLFCOSE_HAVE_AESGCM) || defined(WOLFCOSE_HAVE_AESCCM) if (aesInited != 0) { (void)wc_AesFree(&aes); + (void)wolfCose_ForceZero(&aes, sizeof(aes)); } #endif if (scratch != NULL) { diff --git a/src/wolfcose_hdr.c b/src/wolfcose_hdr.c index 0491fc7..e7f1e00 100644 --- a/src/wolfcose_hdr.c +++ b/src/wolfcose_hdr.c @@ -61,19 +61,20 @@ int wolfCose_InInt32Range(int64_t val) static uint32_t wolfCose_LabelBit(int64_t label) { uint32_t bit; - uint32_t shift; - int64_t shift64; + uint32_t shift = 32u; if ((label >= 1) && (label <= 16)) { - shift64 = label; - shift64--; - shift = (uint32_t)shift64; - bit = ((uint32_t)1u) << shift; + shift = (uint32_t)label; + shift--; } else if ((label <= -1) && (label >= -16)) { - shift64 = -label; - shift = (uint32_t)shift64; + shift = (uint32_t)(-label); shift += 15u; + } + else { + /* No tracked bit. */ + } + if (shift < 32u) { bit = ((uint32_t)1u) << shift; } else { @@ -221,12 +222,17 @@ int wolfCose_DecodeProtectedHdr(const uint8_t* data, size_t dataLen, if ((hdr == NULL) || (hdrState == NULL)) { ret = WOLFCOSE_E_INVALID_ARG; } - else if ((data == NULL) || (dataLen == 0u)) { + else if ((data == NULL) && (dataLen != 0u)) { + ret = WOLFCOSE_E_INVALID_ARG; + } + else if (dataLen == 0u) { /* Empty protected header is valid */ wolfCose_HdrStateInit(hdrState); ret = WOLFCOSE_SUCCESS; } else { + uint8_t contentTypeUnderstood = 0u; + wolfCose_HdrStateInit(hdrState); ctx.cbuf = data; ctx.bufSz = dataLen; @@ -317,6 +323,7 @@ int wolfCose_DecodeProtectedHdr(const uint8_t* data, size_t dataLen, } if (ret == WOLFCOSE_SUCCESS) { hdr->contentType = (int32_t)contentTypeVal; + contentTypeUnderstood = 1u; } } } @@ -366,6 +373,11 @@ int wolfCose_DecodeProtectedHdr(const uint8_t* data, size_t dataLen, ((critLabels & ~hdrState->labelBits) != 0u)) { ret = WOLFCOSE_E_COSE_BAD_HDR; } + if ((ret == WOLFCOSE_SUCCESS) && + ((critLabels & wolfCose_LabelBit(WOLFCOSE_HDR_CONTENT_TYPE)) != + 0u) && (contentTypeUnderstood == 0u)) { + ret = WOLFCOSE_E_COSE_BAD_HDR; + } /* IV and Partial IV are mutually exclusive. */ if ((ret == WOLFCOSE_SUCCESS) && diff --git a/src/wolfcose_mac.c b/src/wolfcose_mac.c index e476036..47d7d62 100644 --- a/src/wolfcose_mac.c +++ b/src/wolfcose_mac.c @@ -624,17 +624,10 @@ int wc_CoseMac_Verify(const WOLFCOSE_RECIPIENT* recipient, ret = WOLFCOSE_E_COSE_BAD_ALG; } - /* COSE_Mac is direct-keyed here and the recipient algorithm is mandatory. */ - if (ret == WOLFCOSE_SUCCESS) { - if (recipientAlgId == WOLFCOSE_ALG_UNSET) { - ret = WOLFCOSE_E_COSE_BAD_ALG; - } - else if (recipientAlgId != WOLFCOSE_ALG_DIRECT) { - ret = WOLFCOSE_E_UNSUPPORTED; - } - else { - /* No action required */ - } + /* COSE_Mac is direct-keyed here. */ + if ((ret == WOLFCOSE_SUCCESS) && + (recipientAlgId != WOLFCOSE_ALG_DIRECT)) { + ret = WOLFCOSE_E_UNSUPPORTED; } if (ret == WOLFCOSE_SUCCESS) { if ((recipientValueIsNull == 0) && (recipientValueLen != 0u)) { diff --git a/src/wolfcose_mac0.c b/src/wolfcose_mac0.c index 780f19d..9b9e033 100644 --- a/src/wolfcose_mac0.c +++ b/src/wolfcose_mac0.c @@ -257,6 +257,7 @@ int wolfCose_AesCbcMac(const uint8_t* key, size_t keyLen, /* Cleanup: always executed */ if (aesInited != 0) { (void)wc_AesFree(&aes); + (void)wolfCose_ForceZero(&aes, sizeof(aes)); } (void)wolfCose_ForceZero(inBlock, sizeof(inBlock)); (void)wolfCose_ForceZero(outBlock, sizeof(outBlock)); diff --git a/tests/test_cose.c b/tests/test_cose.c index 50c94f7..2473f10 100644 --- a/tests/test_cose.c +++ b/tests/test_cose.c @@ -18098,6 +18098,10 @@ static void test_cose_protected_hdr_crit(void) uint8_t critMissing[] = {0xA2u, 0x01u, 0x26u, 0x02u, 0x81u, 0x05u}; /* {1: -7, 2: []} : crit is an empty array -> RFC 9052 rejects */ uint8_t critEmpty[] = {0xA2u, 0x01u, 0x26u, 0x02u, 0x80u}; + /* {2: [3], 3: "x"} : critical tstr content type is not understood */ + uint8_t critTstrContentType[] = { + 0xA2u, 0x02u, 0x81u, 0x03u, 0x03u, 0x61u, 'x' + }; TEST_LOG(" [Protected Header: crit]\n"); XMEMSET(&hdr, 0, sizeof(hdr)); @@ -18123,6 +18127,12 @@ static void test_cose_protected_hdr_crit(void) &hdrState); TEST_ASSERT(ret == WOLFCOSE_E_COSE_BAD_HDR, "DecodeProtectedHdr crit empty array"); + + XMEMSET(&hdr, 0, sizeof(hdr)); + ret = wolfCose_DecodeProtectedHdr(critTstrContentType, + sizeof(critTstrContentType), &hdr, &hdrState); + TEST_ASSERT(ret == WOLFCOSE_E_COSE_BAD_HDR, + "DecodeProtectedHdr rejects critical tstr content-type"); } static void test_cose_cross_bucket_dup(void)