@@ -12268,6 +12268,108 @@ static int test_wc_CheckCertSigPubKey(void)
1226812268 return EXPECT_RESULT();
1226912269}
1227012270
12271+ /* Trailing data after a certificate's outer SEQUENCE must be rejected at parse
12272+ * time on a default (strict) build and tolerated when WOLFSSL_NO_ASN_STRICT is
12273+ * defined. In the latter case the stored/canonical DER (wolfSSL_X509_get_der /
12274+ * wolfSSL_i2d_X509) must still be bounded to the certificate itself and never
12275+ * re-emit the trailing bytes. */
12276+ static int test_cert_trailing_data(void)
12277+ {
12278+ EXPECT_DECLS;
12279+ #if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
12280+ defined(WOLFSSL_PEM_TO_DER)
12281+ const char* ca_cert = "./certs/ca-cert.pem";
12282+ byte* pem = NULL;
12283+ size_t pemSz = 0;
12284+ byte* der = NULL;
12285+ word32 derBufSz = 0;
12286+ int certSz = 0;
12287+ byte* certPlusJunk = NULL;
12288+ word32 certPlusJunkSz = 0;
12289+ const word32 junkSz = 24;
12290+ DecodedCert decoded;
12291+
12292+ /* Load a known-good certificate and convert it to DER. */
12293+ ExpectIntEQ(load_file(ca_cert, &pem, &pemSz), 0);
12294+ derBufSz = (word32)pemSz; /* DER is always smaller than its PEM. */
12295+ ExpectNotNull(der = (byte*)XMALLOC(derBufSz, NULL, DYNAMIC_TYPE_TMP_BUFFER));
12296+ ExpectIntGT(certSz = wc_CertPemToDer(pem, (int)pemSz, der, (int)derBufSz,
12297+ CERT_TYPE), 0);
12298+
12299+ /* Build a buffer holding the certificate followed by N junk bytes. */
12300+ if (certSz > 0) {
12301+ certPlusJunkSz = (word32)certSz + junkSz;
12302+ ExpectNotNull(certPlusJunk = (byte*)XMALLOC(certPlusJunkSz, NULL,
12303+ DYNAMIC_TYPE_TMP_BUFFER));
12304+ }
12305+ if (certPlusJunk != NULL) {
12306+ XMEMCPY(certPlusJunk, der, (size_t)certSz);
12307+ XMEMSET(certPlusJunk + certSz, 0xA5, junkSz);
12308+ }
12309+
12310+ /* Sanity: the clean certificate parses successfully. */
12311+ if (certSz > 0) {
12312+ XMEMSET(&decoded, 0, sizeof(decoded));
12313+ wc_InitDecodedCert(&decoded, der, (word32)certSz, NULL);
12314+ ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL), 0);
12315+ wc_FreeDecodedCert(&decoded);
12316+ }
12317+
12318+ /* Certificate with appended junk. */
12319+ if (certPlusJunk != NULL) {
12320+ XMEMSET(&decoded, 0, sizeof(decoded));
12321+ wc_InitDecodedCert(&decoded, certPlusJunk, certPlusJunkSz, NULL);
12322+ #ifdef WOLFSSL_NO_ASN_STRICT
12323+ /* Opt-out build: trailing data is tolerated at parse time, but srcIdx
12324+ * must stop at the end of the certificate (not the junk). */
12325+ ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL), 0);
12326+ ExpectIntEQ((int)decoded.srcIdx, certSz);
12327+ #else
12328+ /* Default (strict) build: trailing data is rejected. */
12329+ ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL),
12330+ WC_NO_ERR_TRACE(ASN_PARSE_E));
12331+ #endif
12332+ wc_FreeDecodedCert(&decoded);
12333+ }
12334+
12335+ /* derCert bounding: on a non-strict build a certificate with trailing data
12336+ * loads into a WOLFSSL_X509, but wolfSSL_X509_get_der / wolfSSL_i2d_X509
12337+ * must re-emit only the certificate bytes (srcIdx), proving the trailing
12338+ * junk is never stored or re-serialized. */
12339+ #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_NO_ASN_STRICT)
12340+ if (certPlusJunk != NULL) {
12341+ WOLFSSL_X509* x509 = NULL;
12342+ const byte* getDer = NULL;
12343+ int getDerSz = 0;
12344+ byte* i2dDer = NULL;
12345+ int i2dSz = 0;
12346+
12347+ x509 = wolfSSL_X509_load_certificate_buffer(certPlusJunk,
12348+ (int)certPlusJunkSz, WOLFSSL_FILETYPE_ASN1);
12349+ ExpectNotNull(x509);
12350+
12351+ getDer = wolfSSL_X509_get_der(x509, &getDerSz);
12352+ ExpectNotNull(getDer);
12353+ ExpectIntEQ(getDerSz, certSz);
12354+
12355+ ExpectIntEQ((i2dSz = wolfSSL_i2d_X509(x509, &i2dDer)), certSz);
12356+ if (i2dDer != NULL)
12357+ XFREE(i2dDer, HEAP_HINT, DYNAMIC_TYPE_OPENSSL);
12358+
12359+ wolfSSL_X509_free(x509);
12360+ }
12361+ #endif /* OPENSSL_EXTRA && WOLFSSL_NO_ASN_STRICT */
12362+
12363+ if (certPlusJunk != NULL)
12364+ XFREE(certPlusJunk, NULL, DYNAMIC_TYPE_TMP_BUFFER);
12365+ if (der != NULL)
12366+ XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
12367+ if (pem != NULL)
12368+ XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
12369+ #endif
12370+ return EXPECT_RESULT();
12371+ }
12372+
1227112373static int test_wolfSSL_X509_ext_d2i(void)
1227212374{
1227312375 EXPECT_DECLS;
@@ -37009,6 +37111,7 @@ TEST_CASE testCases[] = {
3700937111 TEST_DECL(test_wc_GetPubKeyDerFromCert),
3701037112 TEST_DECL(test_wc_GetSubjectPubKeyInfoDerFromCert),
3701137113 TEST_DECL(test_wc_CheckCertSigPubKey),
37114+ TEST_DECL(test_cert_trailing_data),
3701237115
3701337116 /* wolfCrypt ASN tests */
3701437117 TEST_DECL(test_ToTraditional),
0 commit comments