diff --git a/tests/api/test_asn.c b/tests/api/test_asn.c index e9eab25bdf..e40ff8cf4a 100644 --- a/tests/api/test_asn.c +++ b/tests/api/test_asn.c @@ -1097,6 +1097,47 @@ int test_wc_DecodeRsaPssParams(void) &hash, &mgf, &saltLen), WC_NO_ERR_TRACE(ASN_PARSE_E)); } + /* --- Test 9: trailerField = 1 (trailerFieldBC) => valid in all modes --- */ + /* SEQUENCE { [3] CONSTRUCTED { INTEGER 1 } } = 30 05 a3 03 02 01 01 */ + { + static const byte trailerValid[] = { + 0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x01 + }; + hash = WC_HASH_TYPE_NONE; + mgf = 0; + saltLen = 0; + ExpectIntEQ(wc_DecodeRsaPssParams(trailerValid, + (word32)sizeof(trailerValid), &hash, &mgf, &saltLen), 0); + ExpectIntEQ((int)hash, (int)WC_HASH_TYPE_SHA); + ExpectIntEQ(mgf, WC_MGF1SHA1); + ExpectIntEQ(saltLen, 20); + } + +#ifndef WOLFSSL_NO_ASN_STRICT + /* --- Test 10: trailerField = 2 => ASN_PARSE_E (strict mode) --- */ + /* RFC 8017 A.2.3: trailerField SHALL be trailerFieldBC(1). */ + /* SEQUENCE { [3] CONSTRUCTED { INTEGER 2 } } = 30 05 a3 03 02 01 02 */ + { + static const byte trailerTwo[] = { + 0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x02 + }; + ExpectIntEQ(wc_DecodeRsaPssParams(trailerTwo, + (word32)sizeof(trailerTwo), &hash, &mgf, &saltLen), + WC_NO_ERR_TRACE(ASN_PARSE_E)); + } + + /* --- Test 11: trailerField = 0 => ASN_PARSE_E (strict mode) --- */ + /* SEQUENCE { [3] CONSTRUCTED { INTEGER 0 } } = 30 05 a3 03 02 01 00 */ + { + static const byte trailerZero[] = { + 0x30, 0x05, 0xa3, 0x03, 0x02, 0x01, 0x00 + }; + ExpectIntEQ(wc_DecodeRsaPssParams(trailerZero, + (word32)sizeof(trailerZero), &hash, &mgf, &saltLen), + WC_NO_ERR_TRACE(ASN_PARSE_E)); + } +#endif /* !WOLFSSL_NO_ASN_STRICT */ + #endif /* WC_RSA_PSS && !NO_RSA && !NO_ASN */ return EXPECT_RESULT(); } diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index bb48198a90..099921cc7e 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -8074,6 +8074,9 @@ static int DecodeRsaPssParams(const byte* params, word32 sz, { DECL_ASNGETDATA(dataASN, rsaPssParamsASN_Length); int ret = 0; +#ifndef WOLFSSL_NO_ASN_STRICT + word16 trailerVal = 1; +#endif word16 sLen = 20; /* Default values. */ @@ -8089,6 +8092,10 @@ static int DecodeRsaPssParams(const byte* params, word32 sz, GetASN_OID(&dataASN[RSAPSSPARAMSASN_IDX_MGFHOID], oidHashType); /* Place the salt length into 16-bit var sLen. */ GetASN_Int16Bit(&dataASN[RSAPSSPARAMSASN_IDX_SALTLENINT], &sLen); +#ifndef WOLFSSL_NO_ASN_STRICT + /* Capture trailerField value for RFC 8017 A.2.3 validation. */ + GetASN_Int16Bit(&dataASN[RSAPSSPARAMSASN_IDX_TRAILERINT], &trailerVal); +#endif /* Decode the algorithm identifier. */ ret = GetASN_Items(rsaPssParamsASN, dataASN, rsaPssParamsASN_Length, 1, params, &inOutIdx, sz); @@ -8105,6 +8112,15 @@ static int DecodeRsaPssParams(const byte* params, word32 sz, word32 oid = dataASN[RSAPSSPARAMSASN_IDX_MGFHOID].data.oid.sum; ret = RsaPssHashOidToMgf1(oid, mgf); } +#ifndef WOLFSSL_NO_ASN_STRICT + /* RFC 8017 A.2.3: trailerField SHALL be trailerFieldBC(1). */ + if ((ret == 0) && (dataASN[RSAPSSPARAMSASN_IDX_TRAILERINT].tag != 0)) { + if (trailerVal != 1) { + WOLFSSL_MSG("DecodeRsaPssParams: trailerField must be 1"); + ret = ASN_PARSE_E; + } + } +#endif if (ret == 0) { *saltLen = sLen; } @@ -8251,12 +8267,24 @@ static int DecodeRsaPssParams(const byte* params, word32 sz, } if (ret == 0) { ret = GetInteger16Bit(params, &idx, sz); +#ifndef WOLFSSL_NO_ASN_STRICT + /* RFC 8017 A.2.3: trailerField SHALL be trailerFieldBC(1). */ + if (ret == 1) { + ret = 0; + } + else { + WOLFSSL_MSG("DecodeRsaPssParams: trailerField must be 1"); + if (ret >= 0) + ret = ASN_PARSE_E; + } +#else if (ret > 0) { ret = 0; } else if (ret != 0) { WOLFSSL_MSG("DecodeRsaPssParams: fail at trailer_value"); } +#endif } } }