Skip to content

Commit d98e199

Browse files
committed
JCE: add engineProbe() implementation to WolfSSLKeyStore
1 parent 99415db commit d98e199

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

src/main/java/com/wolfssl/provider/jce/WolfSSLKeyStore.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,6 +1808,62 @@ public synchronized void engineLoad(InputStream stream, char[] password)
18081808
return;
18091809
}
18101810

1811+
/**
1812+
* Probes the specified input stream to determine if it contains a
1813+
* keystore that is supported by this implementation.
1814+
*
1815+
* This method is used by KeyStore.getInstance(File, char[]) and similar
1816+
* methods to auto-detect the keystore type without requiring explicit
1817+
* type specification.
1818+
*
1819+
* Note: engineProbe() was added in JDK 9. No @Override annotation to
1820+
* maintain Java 8 compatibility. On JDK 9+ this method is called by
1821+
* KeyStore for auto-detection; on Java 8 it is simply unused.
1822+
*
1823+
* @param stream the keystore data to be probed. The stream must support
1824+
* mark/reset so the caller can rewind after probing.
1825+
*
1826+
* @return true if the keystore data is supported (has WKS magic number),
1827+
* otherwise false
1828+
*
1829+
* @throws IOException if there is an I/O problem with the keystore data
1830+
* @throws NullPointerException if the stream is null
1831+
*/
1832+
public boolean engineProbe(InputStream stream) throws IOException {
1833+
1834+
int magic = 0;
1835+
DataInputStream dis = null;
1836+
1837+
if (stream == null) {
1838+
throw new NullPointerException("InputStream cannot be null");
1839+
}
1840+
1841+
/* Read first 4 bytes to check magic number */
1842+
stream.mark(4);
1843+
dis = new DataInputStream(stream);
1844+
1845+
try {
1846+
magic = dis.readInt();
1847+
if (magic == WKS_MAGIC_NUMBER) {
1848+
return true;
1849+
}
1850+
}
1851+
catch (IOException e) {
1852+
/* Could not read 4 bytes, not a valid WKS file, swallow
1853+
* exception and return false below. */
1854+
}
1855+
finally {
1856+
try {
1857+
stream.reset();
1858+
}
1859+
catch (IOException e) {
1860+
/* Reset failed, stream may not support mark/reset */
1861+
}
1862+
}
1863+
1864+
return false;
1865+
}
1866+
18111867
/**
18121868
* Internal method for logging output.
18131869
*

src/test/java/com/wolfssl/provider/jce/test/WolfSSLKeyStoreTest.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import javax.crypto.SecretKey;
6868

6969
import com.wolfssl.provider.jce.WolfCryptProvider;
70+
import com.wolfssl.provider.jce.WolfSSLKeyStore;
7071
import com.wolfssl.wolfcrypt.test.TimedTestWatcher;
7172

7273
public class WolfSSLKeyStoreTest {
@@ -2371,5 +2372,81 @@ public void run() {
23712372
assertNotNull(chain);
23722373
assertTrue(chain.length > 0);
23732374
}
2375+
2376+
/**
2377+
* Test that engineProbe() correctly identifies WKS format by checking
2378+
* the magic number at the beginning of the stream.
2379+
*/
2380+
@Test
2381+
public void testEngineProbeIdentifiesWKS()
2382+
throws KeyStoreException, IOException, NoSuchProviderException,
2383+
NoSuchAlgorithmException, CertificateException {
2384+
2385+
/* Create a WKS keystore and store it to a byte array */
2386+
KeyStore store = KeyStore.getInstance(storeType, storeProvider);
2387+
store.load(null, storePass.toCharArray());
2388+
2389+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
2390+
store.store(baos, storePass.toCharArray());
2391+
byte[] wksBytes = baos.toByteArray();
2392+
2393+
/* Get the WolfSSLKeyStore SPI instance via reflection to call
2394+
* engineProbe directly (since KeyStore doesn't expose it) */
2395+
try {
2396+
WolfSSLKeyStore wksSpi = new WolfSSLKeyStore();
2397+
2398+
/* Test that valid WKS data returns true */
2399+
ByteArrayInputStream bais = new ByteArrayInputStream(wksBytes);
2400+
boolean result = wksSpi.engineProbe(bais);
2401+
assertTrue("engineProbe should return true for valid WKS", result);
2402+
2403+
/* Verify stream position is preserved after engineProbe().
2404+
* Per KeyStoreSpi spec, probe should leave stream at original
2405+
* position so other implementations can try. */
2406+
assertEquals("Stream should be at beginning after engineProbe()",
2407+
wksBytes[0] & 0xFF, bais.read());
2408+
2409+
/* Test that invalid data (non-WKS) returns false */
2410+
byte[] invalidData = new byte[] {
2411+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
2412+
};
2413+
bais = new ByteArrayInputStream(invalidData);
2414+
result = wksSpi.engineProbe(bais);
2415+
assertFalse("engineProbe should return false for non-WKS", result);
2416+
2417+
/* Test that JKS magic number returns false
2418+
* JKS magic is 0xFEEDFEED */
2419+
byte[] jksMagic = new byte[] {
2420+
(byte)0xFE, (byte)0xED, (byte)0xFE, (byte)0xED
2421+
};
2422+
bais = new ByteArrayInputStream(jksMagic);
2423+
result = wksSpi.engineProbe(bais);
2424+
assertFalse("engineProbe should return false for JKS", result);
2425+
2426+
/* Test that empty stream returns false */
2427+
bais = new ByteArrayInputStream(new byte[0]);
2428+
result = wksSpi.engineProbe(bais);
2429+
assertFalse("engineProbe should return false for empty stream",
2430+
result);
2431+
2432+
/* Test that stream shorter than 4 bytes returns false */
2433+
bais = new ByteArrayInputStream(new byte[] {0x00, 0x00, 0x00});
2434+
result = wksSpi.engineProbe(bais);
2435+
assertFalse("engineProbe should return false for short stream",
2436+
result);
2437+
2438+
} catch (Exception e) {
2439+
fail("engineProbe test threw exception: " + e.getMessage());
2440+
}
2441+
}
2442+
2443+
/**
2444+
* Test that engineProbe() throws NullPointerException for null stream.
2445+
*/
2446+
@Test(expected = NullPointerException.class)
2447+
public void testEngineProbeNullStream() throws IOException {
2448+
WolfSSLKeyStore wksSpi = new WolfSSLKeyStore();
2449+
wksSpi.engineProbe(null);
2450+
}
23742451
}
23752452

0 commit comments

Comments
 (0)