@@ -80,6 +80,14 @@ public class WolfCryptPKIXRevocationChecker extends PKIXRevocationChecker {
8080 /* Trust anchors for determining if issuer is a trust anchor */
8181 private Set <TrustAnchor > trustAnchors ;
8282
83+ /* Last applied I/O timeout value from wolfjce.ioTimeout property.
84+ * Used to skip redundant JNI calls when multiple checkers or
85+ * repeated init() calls read the same property value. wolfIO_SetTimeout()
86+ * sets a global value, so all checkers in the JVM share the same timeout.
87+ * Integer.MIN_VALUE indicates no timeout has been applied yet. */
88+ private static volatile int lastAppliedIOTimeout =
89+ Integer .MIN_VALUE ;
90+
8391 /**
8492 * Create new WolfCryptPKIXRevocationChecker.
8593 */
@@ -147,6 +155,10 @@ public void init(boolean forward) throws CertPathValidatorException {
147155 this .initialized = true ;
148156 this .softFailExceptions .clear ();
149157
158+ /* Set wolfSSL I/O timeout for HTTP-based operations (OCSP lookups,
159+ * CRL fetching) if 'wolfjce.ioTimeout' System property is set. */
160+ setIOTimeoutFromProperty ();
161+
150162 /* Verify we have OCSP support if needed */
151163 if (!options .contains (Option .PREFER_CRLS )) {
152164 if (!WolfCrypt .OcspEnabled ()) {
@@ -591,6 +603,77 @@ public List<CertPathValidatorException> getSoftFailExceptions() {
591603 return Collections .unmodifiableList (this .softFailExceptions );
592604 }
593605
606+ /**
607+ * Read and apply wolfjce.ioTimeout system property.
608+ *
609+ * Sets the native wolfSSL I/O timeout via wolfIO_SetTimeout()
610+ * if the property is set and valid. If the property is set but
611+ * contains an invalid value, throws CertPathValidatorException
612+ * to fail revocation checker initialization.
613+ *
614+ * Note: The native timeout is a global (process-wide) setting
615+ * shared by all threads and validations in the JVM. To reduce
616+ * redundant JNI calls, the parsed value is compared against
617+ * the last applied value and the native call is skipped if
618+ * unchanged.
619+ *
620+ * @throws CertPathValidatorException if property value is
621+ * invalid (not a number, negative, exceeds max, or
622+ * HAVE_IO_TIMEOUT not compiled in)
623+ */
624+ private void setIOTimeoutFromProperty () throws CertPathValidatorException {
625+
626+ int timeoutSec ;
627+ String ioTimeout ;
628+
629+ try {
630+ ioTimeout = System .getProperty ("wolfjce.ioTimeout" );
631+ } catch (SecurityException e ) {
632+ /* SecurityManager blocked property access, treat as
633+ * property not set and continue without timeout */
634+ return ;
635+ }
636+
637+ if (ioTimeout == null ) {
638+ return ;
639+ }
640+ final String trimmed = ioTimeout .trim ();
641+ if (trimmed .isEmpty ()) {
642+ return ;
643+ }
644+
645+ try {
646+ timeoutSec = Integer .parseInt (trimmed );
647+
648+ /* Skip JNI call if value unchanged from last apply */
649+ if (timeoutSec != lastAppliedIOTimeout ) {
650+ WolfCrypt .setIOTimeout (timeoutSec );
651+ lastAppliedIOTimeout = timeoutSec ;
652+
653+ WolfCryptDebug .log (
654+ WolfCryptPKIXRevocationChecker .class ,
655+ WolfCryptDebug .INFO ,
656+ () -> "wolfjce.ioTimeout set to " +
657+ trimmed + " seconds" );
658+ }
659+
660+ } catch (NumberFormatException e ) {
661+ throw new CertPathValidatorException (
662+ "Invalid wolfjce.ioTimeout value: " + trimmed +
663+ ", must be integer seconds: " + e .getMessage (), e );
664+
665+ } catch (IllegalArgumentException e ) {
666+ throw new CertPathValidatorException (
667+ "Invalid wolfjce.ioTimeout value: " + trimmed +
668+ ": " + e .getMessage (), e );
669+
670+ } catch (WolfCryptException e ) {
671+ throw new CertPathValidatorException (
672+ "wolfjce.ioTimeout set but native wolfSSL not " +
673+ "compiled with HAVE_IO_TIMEOUT: " + e .getMessage (), e );
674+ }
675+ }
676+
594677 /**
595678 * Clone this revocation checker.
596679 *
0 commit comments