Skip to content

Commit 13e83eb

Browse files
authored
Merge pull request #207 from cconlon/fipsCallback
Improve FIPS error diagnostics
2 parents 4967e89 + 4b8767c commit 13e83eb

8 files changed

Lines changed: 233 additions & 108 deletions

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323

2424
import java.security.Provider;
2525
import java.security.Security;
26+
import java.util.concurrent.atomic.AtomicInteger;
2627
import com.wolfssl.wolfcrypt.FeatureDetect;
2728
import com.wolfssl.wolfcrypt.Fips;
29+
import com.wolfssl.wolfcrypt.WolfCryptError;
2830
import com.wolfssl.wolfcrypt.WolfSSLX509StoreCtx;
2931

3032
/**
@@ -34,6 +36,51 @@ public final class WolfCryptProvider extends Provider {
3436

3537
private static final long serialVersionUID = 1L;
3638

39+
/**
40+
* Default FIPS error callback for wolfJCE provider.
41+
*
42+
* Logs FIPS errors to aid in debugging module failures. Registered
43+
* automatically when wolfJCE provider is instantiated with FIPS wolfCrypt.
44+
*/
45+
private static class JCEFIPSErrorCallback implements Fips.ErrorCallback {
46+
47+
/* Track last error code to suppress repeated consecutive messages.
48+
* Native wolfCrypt may call the callback with the same error code
49+
* multiple times during a failure sequence. */
50+
private static final AtomicInteger lastErr = new AtomicInteger(0);
51+
52+
/**
53+
* Called by native wolfCrypt when FIPS error occurs.
54+
*
55+
* @param ok 1 if verification passed, otherwise 0
56+
* @param err wolfCrypt FIPS error code
57+
* @param hash expected verifyCore hash value
58+
*/
59+
@Override
60+
public void errorCallback(int ok, int err, String hash) {
61+
62+
int prev = lastErr.getAndSet(err);
63+
if (prev == err) {
64+
return;
65+
}
66+
67+
String errStr = WolfCryptError.fromInt(err).getDescription();
68+
69+
System.err.println("wolfJCE FIPS error: ok = " + ok + ", err = " +
70+
err + " (" + errStr + "), hash = " + hash);
71+
72+
if (err == WolfCryptError.IN_CORE_FIPS_E.getCode()) {
73+
System.err.println("wolfJCE FIPS: in core integrity hash " +
74+
"check failure. Copy hash above into verifyCore[] in " +
75+
"fips_test.c and rebuild");
76+
}
77+
78+
WolfCryptDebug.log(JCEFIPSErrorCallback.class, WolfCryptDebug.ERROR,
79+
() -> "FIPS error: ok = " + ok + ", err = " + err + " (" +
80+
errStr + "), hash = " + hash);
81+
}
82+
}
83+
3784
/**
3885
* Create new WolfCryptProvider object
3986
*/
@@ -44,6 +91,14 @@ public WolfCryptProvider() {
4491
* WolfCryptDebug class was first loaded (e.g., via JAVA_OPTS) */
4592
WolfCryptDebug.refreshDebugFlags();
4693

94+
/* Register default FIPS error callback if FIPS enabled. */
95+
if (Fips.enabled) {
96+
Fips.wolfCrypt_SetCb_fips(new JCEFIPSErrorCallback());
97+
98+
WolfCryptDebug.log(getClass(), WolfCryptDebug.INFO,
99+
() -> "Registered wolfCrypt FIPS error callback");
100+
}
101+
47102
registerServices();
48103
}
49104

src/main/java/com/wolfssl/wolfcrypt/WolfCryptException.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,45 @@ public WolfCryptException(String reason) {
4747
* @param code wolfCrypt error code
4848
*/
4949
public WolfCryptException(int code) {
50-
super(WolfCryptError.fromInt(code).getDescription());
50+
super(getErrorMessage(code));
5151

5252
this.error = WolfCryptError.fromInt(code);
5353
this.code = code;
5454
}
5555

56+
/**
57+
* Build exception message from error code. For FIPS_NOT_ALLOWED_E
58+
* errors, queries and appends the current FIPS module status to help
59+
* diagnose the root cause.
60+
*
61+
* @param code wolfCrypt error code
62+
* @return descriptive error message string
63+
*/
64+
private static String getErrorMessage(int code) {
65+
66+
String msg = WolfCryptError.fromInt(code).getDescription();
67+
68+
/* Get module status for root cause of FIPS not allowed failure */
69+
if (code == WolfCryptError.FIPS_NOT_ALLOWED_E.getCode()) {
70+
try {
71+
if (Fips.enabled) {
72+
int status = Fips.wolfCrypt_GetStatus_fips();
73+
if (status != 0) {
74+
String statusDesc =
75+
WolfCryptError.fromInt(status).getDescription();
76+
msg += " [FIPS module status: " + status + " (" +
77+
statusDesc + ")]";
78+
}
79+
}
80+
}
81+
catch (Exception e) {
82+
/* FIPS status query not available */
83+
}
84+
}
85+
86+
return msg;
87+
}
88+
5689
/**
5790
* Create new WolfCryptException from reason and cause
5891
*

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -314,27 +314,33 @@ public void testMd5Threaded()
314314
service.submit(new Runnable() {
315315
@Override public void run() {
316316

317-
MessageDigest md5 = null;
318-
319317
try {
320-
md5 = MessageDigest.getInstance(
321-
"MD5", "wolfJCE");
322-
} catch (NoSuchAlgorithmException |
323-
NoSuchProviderException e) {
324-
/* add empty array on failure, will error out below */
318+
MessageDigest md5 = null;
319+
320+
try {
321+
md5 = MessageDigest.getInstance(
322+
"MD5", "wolfJCE");
323+
} catch (NoSuchAlgorithmException |
324+
NoSuchProviderException e) {
325+
results.add(new byte[] {0});
326+
return;
327+
}
328+
329+
/* process/update in 1024-byte chunks */
330+
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
331+
md5.update(rand10kBuf, j, 1024);
332+
}
333+
334+
/* get final hash */
335+
byte[] hash = md5.digest();
336+
results.add(hash.clone());
337+
338+
} catch (Exception e) {
339+
/* ensure result added so iterator is not empty */
325340
results.add(new byte[] {0});
341+
} finally {
342+
latch.countDown();
326343
}
327-
328-
/* process/update in 1024-byte chunks */
329-
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
330-
md5.update(rand10kBuf, j, 1024);
331-
}
332-
333-
/* get final hash */
334-
byte[] hash = md5.digest();
335-
results.add(hash.clone());
336-
337-
latch.countDown();
338344
}
339345
});
340346
}

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -303,27 +303,33 @@ public void testSha256Threaded()
303303
service.submit(new Runnable() {
304304
@Override public void run() {
305305

306-
MessageDigest sha = null;
307-
308306
try {
309-
sha = MessageDigest.getInstance(
310-
"SHA-256", "wolfJCE");
311-
} catch (NoSuchAlgorithmException |
312-
NoSuchProviderException e) {
313-
/* add empty array on failure, will error out below */
307+
MessageDigest sha = null;
308+
309+
try {
310+
sha = MessageDigest.getInstance(
311+
"SHA-256", "wolfJCE");
312+
} catch (NoSuchAlgorithmException |
313+
NoSuchProviderException e) {
314+
results.add(new byte[] {0});
315+
return;
316+
}
317+
318+
/* process/update in 1024-byte chunks */
319+
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
320+
sha.update(rand10kBuf, j, 1024);
321+
}
322+
323+
/* get final hash */
324+
byte[] hash = sha.digest();
325+
results.add(hash.clone());
326+
327+
} catch (Exception e) {
328+
/* ensure result added so iterator is not empty */
314329
results.add(new byte[] {0});
330+
} finally {
331+
latch.countDown();
315332
}
316-
317-
/* process/update in 1024-byte chunks */
318-
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
319-
sha.update(rand10kBuf, j, 1024);
320-
}
321-
322-
/* get final hash */
323-
byte[] hash = sha.digest();
324-
results.add(hash.clone());
325-
326-
latch.countDown();
327333
}
328334
});
329335
}

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -326,27 +326,33 @@ public void testSha384Threaded()
326326
service.submit(new Runnable() {
327327
@Override public void run() {
328328

329-
MessageDigest sha = null;
330-
331329
try {
332-
sha = MessageDigest.getInstance(
333-
"SHA-384", "wolfJCE");
334-
} catch (NoSuchAlgorithmException |
335-
NoSuchProviderException e) {
336-
/* add empty array on failure, will error out below */
330+
MessageDigest sha = null;
331+
332+
try {
333+
sha = MessageDigest.getInstance(
334+
"SHA-384", "wolfJCE");
335+
} catch (NoSuchAlgorithmException |
336+
NoSuchProviderException e) {
337+
results.add(new byte[] {0});
338+
return;
339+
}
340+
341+
/* process/update in 1024-byte chunks */
342+
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
343+
sha.update(rand10kBuf, j, 1024);
344+
}
345+
346+
/* get final hash */
347+
byte[] hash = sha.digest();
348+
results.add(hash.clone());
349+
350+
} catch (Exception e) {
351+
/* ensure result added so iterator is not empty */
337352
results.add(new byte[] {0});
353+
} finally {
354+
latch.countDown();
338355
}
339-
340-
/* process/update in 1024-byte chunks */
341-
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
342-
sha.update(rand10kBuf, j, 1024);
343-
}
344-
345-
/* get final hash */
346-
byte[] hash = sha.digest();
347-
results.add(hash.clone());
348-
349-
latch.countDown();
350356
}
351357
});
352358
}

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

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -337,26 +337,33 @@ public void testSha3Threaded()
337337
service.submit(new Runnable() {
338338
@Override public void run() {
339339

340-
MessageDigest sha3 = null;
341-
342340
try {
343-
sha3 = MessageDigest.getInstance("SHA3-256", "wolfJCE");
344-
} catch (NoSuchAlgorithmException |
345-
NoSuchProviderException e) {
346-
/* Add empty array on failure, will error out below */
341+
MessageDigest sha3 = null;
342+
343+
try {
344+
sha3 = MessageDigest.getInstance(
345+
"SHA3-256", "wolfJCE");
346+
} catch (NoSuchAlgorithmException |
347+
NoSuchProviderException e) {
348+
results.add(new byte[] {0});
349+
return;
350+
}
351+
352+
/* Process/update in 1024-byte chunks */
353+
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
354+
sha3.update(rand10kBuf, j, 1024);
355+
}
356+
357+
/* Get final hash */
358+
byte[] hash = sha3.digest();
359+
results.add(hash.clone());
360+
361+
} catch (Exception e) {
362+
/* ensure result added so iterator is not empty */
347363
results.add(new byte[] {0});
364+
} finally {
365+
latch.countDown();
348366
}
349-
350-
/* Process/update in 1024-byte chunks */
351-
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
352-
sha3.update(rand10kBuf, j, 1024);
353-
}
354-
355-
/* Get final hash */
356-
byte[] hash = sha3.digest();
357-
results.add(hash.clone());
358-
359-
latch.countDown();
360367
}
361368
});
362369
}

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -346,27 +346,33 @@ public void testSha512Threaded()
346346
service.submit(new Runnable() {
347347
@Override public void run() {
348348

349-
MessageDigest sha = null;
350-
351349
try {
352-
sha = MessageDigest.getInstance(
353-
"SHA-512", "wolfJCE");
354-
} catch (NoSuchAlgorithmException |
355-
NoSuchProviderException e) {
356-
/* add empty array on failure, will error out below */
350+
MessageDigest sha = null;
351+
352+
try {
353+
sha = MessageDigest.getInstance(
354+
"SHA-512", "wolfJCE");
355+
} catch (NoSuchAlgorithmException |
356+
NoSuchProviderException e) {
357+
results.add(new byte[] {0});
358+
return;
359+
}
360+
361+
/* process/update in 1024-byte chunks */
362+
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
363+
sha.update(rand10kBuf, j, 1024);
364+
}
365+
366+
/* get final hash */
367+
byte[] hash = sha.digest();
368+
results.add(hash.clone());
369+
370+
} catch (Exception e) {
371+
/* ensure result added so iterator is not empty */
357372
results.add(new byte[] {0});
373+
} finally {
374+
latch.countDown();
358375
}
359-
360-
/* process/update in 1024-byte chunks */
361-
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
362-
sha.update(rand10kBuf, j, 1024);
363-
}
364-
365-
/* get final hash */
366-
byte[] hash = sha.digest();
367-
results.add(hash.clone());
368-
369-
latch.countDown();
370376
}
371377
});
372378
}

0 commit comments

Comments
 (0)