diff --git a/.github/workflows/windows-vs.yml b/.github/workflows/windows-vs.yml index 5be1dfe9..b58bb0d0 100644 --- a/.github/workflows/windows-vs.yml +++ b/.github/workflows/windows-vs.yml @@ -274,7 +274,7 @@ jobs: $content = Get-Content $userSettingsPath -Raw Write-Output "Original file size: $($content.Length) characters" - $newDefines = "#define WOLFSSL_KEY_GEN`n#define HAVE_CRL`n#define OPENSSL_ALL`n`n" + $newDefines = "#define WOLFSSL_KEY_GEN`n#define HAVE_CRL`n#define OPENSSL_ALL`n#define WOLFSSL_SHA224`n`n" # Try multiple possible insertion points $insertPoints = @( diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java index 36721887..8c18f3f7 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java @@ -38,6 +38,11 @@ public final class WolfCryptProvider extends Provider { */ public WolfCryptProvider() { super("wolfJCE", 1.8, "wolfCrypt JCE Provider"); + + /* Refresh debug flags in case system properties were set after + * WolfCryptDebug class was first loaded (e.g., via JAVA_OPTS) */ + WolfCryptDebug.refreshDebugFlags(); + registerServices(); } diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptRandom.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptRandom.java index 3c24e5de..805e1ff1 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptRandom.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptRandom.java @@ -52,19 +52,19 @@ public WolfCryptRandom() { } @Override - protected byte[] engineGenerateSeed(int numBytes) { + protected synchronized byte[] engineGenerateSeed(int numBytes) { return rng.generateBlock(numBytes); } @Override - protected void engineNextBytes(byte[] bytes) { + protected synchronized void engineNextBytes(byte[] bytes) { rng.generateBlock(bytes); } @Override - protected void engineSetSeed(byte[] seed) { + protected synchronized void engineSetSeed(byte[] seed) { /* wolfCrypt reseeds internally automatically */ log("setSeed() not supported by wolfJCE"); } @@ -75,7 +75,7 @@ private void log(String msg) { @SuppressWarnings("deprecation") @Override - protected void finalize() throws Throwable { + protected synchronized void finalize() throws Throwable { try { if (this.rng != null) { @@ -98,7 +98,9 @@ protected void finalize() throws Throwable { * * @throws IOException on error writing to ObjectOutputStream */ - private void writeObject(ObjectOutputStream out) throws IOException { + private synchronized void writeObject(ObjectOutputStream out) + throws IOException { + if (this.rng != null) { this.rng.free(); this.rng.releaseNativeStruct(); @@ -118,7 +120,7 @@ private void writeObject(ObjectOutputStream out) throws IOException { * @throws IOException on error reading from ObjectInputStream * @throws ClassNotFoundException if object class not found */ - private void readObject(ObjectInputStream in) + private synchronized void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { if (rng == null) { diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java index f3d05e03..d6a07cf5 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java @@ -126,6 +126,9 @@ enum PaddingType { private Rng rng = null; private final Object rngLock = new Object(); + /* Lock for hash object synchronization */ + private final Object hashLock = new Object(); + /** * Create a WolfCryptSignature instance with the specified key type * and digest type. @@ -390,37 +393,39 @@ protected synchronized void engineInitSign(PrivateKey privateKey) return; } - switch (this.digestType) { - case WC_MD5: - this.md5.init(); - break; + synchronized (hashLock) { + switch (this.digestType) { + case WC_MD5: + this.md5.init(); + break; - case WC_SHA1: - this.sha.init(); - break; + case WC_SHA1: + this.sha.init(); + break; - case WC_SHA224: - this.sha224.init(); - break; + case WC_SHA224: + this.sha224.init(); + break; - case WC_SHA256: - this.sha256.init(); - break; + case WC_SHA256: + this.sha256.init(); + break; - case WC_SHA384: - this.sha384.init(); - break; + case WC_SHA384: + this.sha384.init(); + break; - case WC_SHA512: - this.sha512.init(); - break; + case WC_SHA512: + this.sha512.init(); + break; - case WC_SHA3_224: - case WC_SHA3_256: - case WC_SHA3_384: - case WC_SHA3_512: - this.sha3.init(); - break; + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.init(); + break; + } } log("init sign with PrivateKey"); @@ -473,36 +478,39 @@ protected synchronized void engineInitVerify(PublicKey publicKey) return; } - switch (this.digestType) { - case WC_MD5: - this.md5.init(); - break; + synchronized (hashLock) { + switch (this.digestType) { + case WC_MD5: + this.md5.init(); + break; - case WC_SHA1: - this.sha.init(); - break; + case WC_SHA1: + this.sha.init(); + break; - case WC_SHA224: - this.sha224.init(); - break; + case WC_SHA224: + this.sha224.init(); + break; - case WC_SHA256: - this.sha256.init(); - break; + case WC_SHA256: + this.sha256.init(); + break; - case WC_SHA384: - this.sha384.init(); - break; + case WC_SHA384: + this.sha384.init(); + break; - case WC_SHA512: - this.sha512.init(); - break; + case WC_SHA512: + this.sha512.init(); + break; - case WC_SHA3_224: - case WC_SHA3_256: - case WC_SHA3_384: - case WC_SHA3_512: - this.sha3.init(); + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.init(); + break; + } } log("init verify with PublicKey"); @@ -600,37 +608,39 @@ protected synchronized byte[] engineSign() throws SignatureException { /* get final digest */ try { - switch (this.digestType) { - case WC_MD5: - this.md5.digest(digest); - break; - - case WC_SHA1: - this.sha.digest(digest); - break; - - case WC_SHA224: - this.sha224.digest(digest); - break; - - case WC_SHA256: - this.sha256.digest(digest); - break; - - case WC_SHA384: - this.sha384.digest(digest); - break; - - case WC_SHA512: - this.sha512.digest(digest); - break; - - case WC_SHA3_224: - case WC_SHA3_256: - case WC_SHA3_384: - case WC_SHA3_512: - this.sha3.digest(digest); - break; + synchronized (hashLock) { + switch (this.digestType) { + case WC_MD5: + this.md5.digest(digest); + break; + + case WC_SHA1: + this.sha.digest(digest); + break; + + case WC_SHA224: + this.sha224.digest(digest); + break; + + case WC_SHA256: + this.sha256.digest(digest); + break; + + case WC_SHA384: + this.sha384.digest(digest); + break; + + case WC_SHA512: + this.sha512.digest(digest); + break; + + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.digest(digest); + break; + } } } catch (ShortBufferException e) { throw new SignatureException(e.getMessage()); @@ -676,10 +686,8 @@ protected synchronized byte[] engineSign() throws SignatureException { case WC_ECDSA: - /* ECC sign */ - synchronized (rngLock) { - signature = this.ecc.sign(digest, this.rng); - } + /* Ecc.sign() internally has a rngLock unlike Rsa.sign() */ + signature = this.ecc.sign(digest, this.rng); break; @@ -719,36 +727,39 @@ protected synchronized void engineUpdate(byte[] b, int off, int len) "Parameters must be set before updating with RSASSA-PSS"); } - switch (this.digestType) { - case WC_MD5: - this.md5.update(b, off, len); - break; + synchronized (hashLock) { + switch (this.digestType) { + case WC_MD5: + this.md5.update(b, off, len); + break; - case WC_SHA1: - this.sha.update(b, off, len); - break; + case WC_SHA1: + this.sha.update(b, off, len); + break; - case WC_SHA224: - this.sha224.update(b, off, len); - break; + case WC_SHA224: + this.sha224.update(b, off, len); + break; - case WC_SHA256: - this.sha256.update(b, off, len); - break; + case WC_SHA256: + this.sha256.update(b, off, len); + break; - case WC_SHA384: - this.sha384.update(b, off, len); - break; + case WC_SHA384: + this.sha384.update(b, off, len); + break; - case WC_SHA512: - this.sha512.update(b, off, len); - break; + case WC_SHA512: + this.sha512.update(b, off, len); + break; - case WC_SHA3_224: - case WC_SHA3_256: - case WC_SHA3_384: - case WC_SHA3_512: - this.sha3.update(b, off, len); + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.update(b, off, len); + break; + } } log("update, offset: " + off + ", len: " + len); @@ -774,37 +785,39 @@ protected synchronized boolean engineVerify(byte[] sigBytes) /* get final digest */ try { - switch (this.digestType) { - case WC_MD5: - this.md5.digest(digest); - break; - - case WC_SHA1: - this.sha.digest(digest); - break; - - case WC_SHA224: - this.sha224.digest(digest); - break; - - case WC_SHA256: - this.sha256.digest(digest); - break; - - case WC_SHA384: - this.sha384.digest(digest); - break; - - case WC_SHA512: - this.sha512.digest(digest); - break; - - case WC_SHA3_224: - case WC_SHA3_256: - case WC_SHA3_384: - case WC_SHA3_512: - this.sha3.digest(digest); - break; + synchronized (hashLock) { + switch (this.digestType) { + case WC_MD5: + this.md5.digest(digest); + break; + + case WC_SHA1: + this.sha.digest(digest); + break; + + case WC_SHA224: + this.sha224.digest(digest); + break; + + case WC_SHA256: + this.sha256.digest(digest); + break; + + case WC_SHA384: + this.sha384.digest(digest); + break; + + case WC_SHA512: + this.sha512.digest(digest); + break; + + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.digest(digest); + break; + } } } catch (ShortBufferException e) { @@ -1150,33 +1163,35 @@ private boolean isDigestSupported(String digestAlg) { * Release existing hash objects to prevent memory leaks */ private void releaseHashObjects() { - if (this.md5 != null) { - this.md5.releaseNativeStruct(); - this.md5 = null; - } - if (this.sha != null) { - this.sha.releaseNativeStruct(); - this.sha = null; - } - if (this.sha224 != null) { - this.sha224.releaseNativeStruct(); - this.sha224 = null; - } - if (this.sha256 != null) { - this.sha256.releaseNativeStruct(); - this.sha256 = null; - } - if (this.sha384 != null) { - this.sha384.releaseNativeStruct(); - this.sha384 = null; - } - if (this.sha512 != null) { - this.sha512.releaseNativeStruct(); - this.sha512 = null; - } - if (this.sha3 != null) { - this.sha3.releaseNativeStruct(); - this.sha3 = null; + synchronized (hashLock) { + if (this.md5 != null) { + this.md5.releaseNativeStruct(); + this.md5 = null; + } + if (this.sha != null) { + this.sha.releaseNativeStruct(); + this.sha = null; + } + if (this.sha224 != null) { + this.sha224.releaseNativeStruct(); + this.sha224 = null; + } + if (this.sha256 != null) { + this.sha256.releaseNativeStruct(); + this.sha256 = null; + } + if (this.sha384 != null) { + this.sha384.releaseNativeStruct(); + this.sha384 = null; + } + if (this.sha512 != null) { + this.sha512.releaseNativeStruct(); + this.sha512 = null; + } + if (this.sha3 != null) { + this.sha3.releaseNativeStruct(); + this.sha3 = null; + } } } @@ -1184,31 +1199,33 @@ private void releaseHashObjects() { * Initialize hash object based on current digest type */ private void initHashObject() { - switch (this.digestType) { - case WC_MD5: - this.md5.init(); - break; - case WC_SHA1: - this.sha.init(); - break; - case WC_SHA224: - this.sha224.init(); - break; - case WC_SHA256: - this.sha256.init(); - break; - case WC_SHA384: - this.sha384.init(); - break; - case WC_SHA512: - this.sha512.init(); - break; - case WC_SHA3_224: - case WC_SHA3_256: - case WC_SHA3_384: - case WC_SHA3_512: - this.sha3.init(); - break; + synchronized (hashLock) { + switch (this.digestType) { + case WC_MD5: + this.md5.init(); + break; + case WC_SHA1: + this.sha.init(); + break; + case WC_SHA224: + this.sha224.init(); + break; + case WC_SHA256: + this.sha256.init(); + break; + case WC_SHA384: + this.sha384.init(); + break; + case WC_SHA512: + this.sha512.init(); + break; + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.init(); + break; + } } } diff --git a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptSignatureTest.java b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptSignatureTest.java index a739b7cc..9b0c5d82 100644 --- a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptSignatureTest.java +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptSignatureTest.java @@ -255,59 +255,183 @@ public void testWolfSignInitMulti() /* Collect diagnostic information for sporadic failures */ StringBuilder diagnostics = new StringBuilder(); - /* Algorithm Context */ - diagnostics.append("FAILURE DETAILS:\n"); - diagnostics.append(" Algorithm: ") + /* Test Details */ + diagnostics.append("Algorithm: ") .append(enabledAlgos.get(i)).append("\n"); - diagnostics.append(" Loop iteration: ").append(i).append("\n"); - diagnostics.append(" Total enabled algorithms: ") + diagnostics.append("Loop iteration: ").append(i).append("\n"); + diagnostics.append("Total enabled algorithms: ") .append(enabledAlgos.size()).append("\n"); - - /* Signature Byte Analysis */ - diagnostics.append(" Signature length: ").append( - signature.length).append("\n"); - if (signature.length > 0) { - diagnostics.append(" Signature first 8 bytes: "); - for (int b = 0; b < Math.min(8, signature.length); b++) { - diagnostics.append(String.format("%02X ", - signature[b])); - } - diagnostics.append("\n"); - diagnostics.append(" Signature has leading zeros: ") - .append(signature[0] == 0).append("\n"); - } + diagnostics.append("Test Message: \"") + .append(toSign).append("\"\n"); + diagnostics.append("Test Message Bytes (hex): ") + .append(bytesToHex(toSignBuf, 0, toSignBuf.length)) + .append("\n"); + + /* Provider Information */ + diagnostics.append("Signer Provider: ") + .append(signer.getProvider().getName()) + .append(" v").append(signer.getProvider().getVersion()) + .append("\n"); + diagnostics.append("Signer Provider Info: ") + .append(signer.getProvider().getInfo()).append("\n"); + diagnostics.append("Verifier Provider: ") + .append(verifier.getProvider().getName()) + .append(" v").append(verifier.getProvider().getVersion()) + .append("\n"); + diagnostics.append("Verifier Provider Info: ") + .append(verifier.getProvider().getInfo()).append("\n"); /* Key Information */ - diagnostics.append(" Private key algorithm: ") + diagnostics.append("Private Key Algorithm: ") .append(priv.getAlgorithm()).append("\n"); - diagnostics.append(" Public key algorithm: ") - .append(pub.getAlgorithm()).append("\n"); - diagnostics.append(" Private key format: ") + diagnostics.append("Private Key Format: ") .append(priv.getFormat()).append("\n"); - diagnostics.append(" Public key format: "). - append(pub.getFormat()).append("\n"); + diagnostics.append("Public Key Algorithm: ") + .append(pub.getAlgorithm()).append("\n"); + diagnostics.append("Public Key Format: ") + .append(pub.getFormat()).append("\n"); + /* RSA Specific Information */ if (priv instanceof java.security.interfaces.RSAPrivateKey) { java.security.interfaces.RSAPrivateKey rsaPriv = (java.security.interfaces.RSAPrivateKey) priv; - diagnostics.append(" RSA key size: ") - .append(rsaPriv.getModulus().bitLength()).append("\n"); + java.security.interfaces.RSAPublicKey rsaPub = + (java.security.interfaces.RSAPublicKey) pub; + + diagnostics.append("RSA Key Size: ") + .append(rsaPriv.getModulus().bitLength()) + .append(" bits\n"); + diagnostics.append("RSA Modulus (hex): ") + .append(rsaPriv.getModulus().toString(16)) + .append("\n"); + diagnostics.append("RSA Private Exponent (hex): ") + .append(rsaPriv.getPrivateExponent().toString(16)) + .append("\n"); + diagnostics.append("RSA Public Exponent: ") + .append(rsaPub.getPublicExponent().toString()) + .append("\n"); + } + + /* ECC Specific Information */ + if (priv instanceof java.security.interfaces.ECPrivateKey) { + java.security.interfaces.ECPrivateKey ecPriv = + (java.security.interfaces.ECPrivateKey) priv; + java.security.interfaces.ECPublicKey ecPub = + (java.security.interfaces.ECPublicKey) pub; + + diagnostics.append("EC Curve: ") + .append(ecPriv.getParams().getCurve()).append("\n"); + diagnostics.append("EC Field Size: ") + .append(ecPriv.getParams().getCurve().getField() + .getFieldSize()).append("\n"); + diagnostics.append("EC Order: ") + .append(ecPriv.getParams().getOrder()).append("\n"); + diagnostics.append("EC Cofactor: ") + .append(ecPriv.getParams().getCofactor()).append("\n"); + + /* Try to determine curve name for reproduction */ + try { + java.security.spec.ECParameterSpec params = + ecPriv.getParams(); + if (params.getCurve().getField() + .getFieldSize() == 256) { + diagnostics.append( + "Likely Curve Name: secp256r1/prime256v1\n"); + } else if (params.getCurve().getField() + .getFieldSize() == 384) { + diagnostics.append( + "Likely Curve Name: secp384r1\n"); + } else if (params.getCurve().getField() + .getFieldSize() == 521) { + diagnostics.append( + "Likely Curve Name: secp521r1\n"); + } + } catch (Exception e) { + diagnostics.append("Could not determine curve name\n"); + } + + /* Private key S value (full key for test reproduction) */ + byte[] sBytes = ecPriv.getS().toByteArray(); + diagnostics.append("Private Key S (full): ") + .append(bytesToHex(sBytes, 0, sBytes.length)) + .append("\n"); + diagnostics.append("Private Key S (decimal): ") + .append(ecPriv.getS().toString()).append("\n"); + + /* Public key point (full coordinates for test repro) */ + diagnostics.append("Public Key X (hex): ") + .append(ecPub.getW().getAffineX().toString(16)) + .append("\n"); + diagnostics.append("Public Key Y (hex): ") + .append(ecPub.getW().getAffineY().toString(16)) + .append("\n"); + diagnostics.append("Public Key X (decimal): ") + .append(ecPub.getW().getAffineX().toString()) + .append("\n"); + diagnostics.append("Public Key Y (decimal): ") + .append(ecPub.getW().getAffineY().toString()) + .append("\n"); } - /* Signature Object State */ - diagnostics.append(" Signer provider: ") - .append(signer.getProvider().getName()).append("\n"); - diagnostics.append(" Verifier provider: ") - .append(verifier.getProvider().getName()).append("\n"); - diagnostics.append(" Signer algorithm: ") - .append(signer.getAlgorithm()).append("\n"); - diagnostics.append(" Verifier algorithm: ") - .append(verifier.getAlgorithm()).append("\n"); + /* Key encoding for reproduction */ + if (priv.getEncoded() != null) { + diagnostics.append("Private Key Encoded (hex): ") + .append(bytesToHex(priv.getEncoded(), 0, + priv.getEncoded().length)) + .append("\n"); + } + if (pub.getEncoded() != null) { + diagnostics.append("Public Key Encoded (hex): ") + .append(bytesToHex(pub.getEncoded(), 0, + pub.getEncoded().length)) + .append("\n"); + } + + /* Signature Information */ + diagnostics.append("Signature Length: ") + .append(signature.length).append(" bytes\n"); + diagnostics.append("Signature (hex): ") + .append(bytesToHex(signature, 0, signature.length)) + .append("\n"); + + /* ASN.1 Analysis for ECDSA/DSA signatures */ + if (signature.length > 6 && signature[0] == 0x30) { + diagnostics.append("ASN.1 SEQUENCE Length: ") + .append(signature[1] & 0xFF).append("\n"); + if (signature[2] == 0x02) { + int rLen = signature[3] & 0xFF; + diagnostics.append("ASN.1 R Length: ") + .append(rLen).append("\n"); + if (4 + rLen < signature.length && + signature[4 + rLen] == 0x02) { + int sLen = signature[5 + rLen] & 0xFF; + diagnostics.append("ASN.1 S Length: ") + .append(sLen).append("\n"); + } + } + } + + /* Timing and Thread Information */ + diagnostics.append("Failure Timestamp: ") + .append(System.currentTimeMillis()).append("\n"); + diagnostics.append("Thread ID: ") + .append(Thread.currentThread().getId()).append("\n"); + diagnostics.append("Thread Name: ") + .append(Thread.currentThread().getName()).append("\n"); + + /* All Available Providers */ + diagnostics.append("All Available Providers:\n"); + Provider[] allProviders = Security.getProviders(); + for (Provider p : allProviders) { + diagnostics.append(" ").append(p.getName()) + .append(" v").append(p.getVersion()) + .append(" - ").append(p.getInfo()).append("\n"); + } + System.err.println(diagnostics.toString()); fail("Signature verification failed when generating and " + - "verifying with wolfJCE provider.\n" + - diagnostics.toString()); + "verifying with wolfJCE provider."); } } } @@ -368,9 +492,164 @@ public void testWolfSignInteropVerify() boolean verified = verifier.verify(signature); if (verified != true) { + /* Collect diagnostic information for sporadic failures */ + StringBuilder diagnostics = new StringBuilder(); + + /* Test Details */ + diagnostics.append("Algorithm: ") + .append(enabledAlgos.get(i)).append("\n"); + diagnostics.append("Test Message: \"") + .append(toSign).append("\"\n"); + diagnostics.append("Test Message Bytes (hex): ") + .append(bytesToHex(toSignBuf, 0, toSignBuf.length)) + .append("\n"); + + /* Provider Information */ + diagnostics.append("Signer Provider: ") + .append(signer.getProvider().getName()) + .append(" v").append(signer.getProvider().getVersion()) + .append("\n"); + diagnostics.append("Signer Provider Info: ") + .append(signer.getProvider().getInfo()).append("\n"); + diagnostics.append("Verifier Provider: ") + .append(verifier.getProvider().getName()) + .append(" v").append(verifier.getProvider().getVersion()) + .append("\n"); + diagnostics.append("Verifier Provider Info: ") + .append(verifier.getProvider().getInfo()).append("\n"); + + /* Key Information */ + diagnostics.append("Private Key Algorithm: ") + .append(priv.getAlgorithm()).append("\n"); + diagnostics.append("Private Key Format: ") + .append(priv.getFormat()).append("\n"); + diagnostics.append("Public Key Algorithm: ") + .append(pub.getAlgorithm()).append("\n"); + diagnostics.append("Public Key Format: ") + .append(pub.getFormat()).append("\n"); + + /* ECC Specific Information */ + if (priv instanceof java.security.interfaces.ECPrivateKey) { + java.security.interfaces.ECPrivateKey ecPriv = + (java.security.interfaces.ECPrivateKey) priv; + java.security.interfaces.ECPublicKey ecPub = + (java.security.interfaces.ECPublicKey) pub; + + diagnostics.append("EC Curve: ") + .append(ecPriv.getParams().getCurve()).append("\n"); + diagnostics.append("EC Field Size: ") + .append(ecPriv.getParams().getCurve().getField() + .getFieldSize()).append("\n"); + diagnostics.append("EC Order: ") + .append(ecPriv.getParams().getOrder()).append("\n"); + diagnostics.append("EC Cofactor: ") + .append(ecPriv.getParams().getCofactor()).append("\n"); + + /* Try to determine curve name for reproduction */ + try { + java.security.spec.ECParameterSpec params = + ecPriv.getParams(); + if (params.getCurve().getField() + .getFieldSize() == 256) { + diagnostics.append( + "Likely Curve Name: secp256r1/prime256v1\n"); + } else if (params.getCurve().getField() + .getFieldSize() == 384) { + diagnostics.append( + "Likely Curve Name: secp384r1\n"); + } else if (params.getCurve().getField() + .getFieldSize() == 521) { + diagnostics.append( + "Likely Curve Name: secp521r1\n"); + } + } catch (Exception e) { + diagnostics.append("Could not determine curve name\n"); + } + + /* Private key S value (full key for test reproduction) */ + byte[] sBytes = ecPriv.getS().toByteArray(); + diagnostics.append("Private Key S (full): ") + .append(bytesToHex(sBytes, 0, sBytes.length)) + .append("\n"); + diagnostics.append("Private Key S (decimal): ") + .append(ecPriv.getS().toString()).append("\n"); + + /* Public key point (full coordinates for test repro) */ + diagnostics.append("Public Key X (hex): ") + .append(ecPub.getW().getAffineX().toString(16)) + .append("\n"); + diagnostics.append("Public Key Y (hex): ") + .append(ecPub.getW().getAffineY().toString(16)) + .append("\n"); + diagnostics.append("Public Key X (decimal): ") + .append(ecPub.getW().getAffineX().toString()) + .append("\n"); + diagnostics.append("Public Key Y (decimal): ") + .append(ecPub.getW().getAffineY().toString()) + .append("\n"); + + /* Key encoding for complete reproduction */ + if (priv.getEncoded() != null) { + diagnostics.append("Private Key Encoded (hex): ") + .append(bytesToHex(priv.getEncoded(), 0, + priv.getEncoded().length)) + .append("\n"); + } + if (pub.getEncoded() != null) { + diagnostics.append("Public Key Encoded (hex): ") + .append(bytesToHex(pub.getEncoded(), 0, + pub.getEncoded().length)) + .append("\n"); + } + } + + /* Signature Information */ + diagnostics.append("Signature Length: ") + .append(signature.length).append(" bytes\n"); + diagnostics.append("Signature (hex): ") + .append(bytesToHex(signature, 0, signature.length)) + .append("\n"); + + /* ASN.1 Analysis */ + if (signature.length > 6 && signature[0] == 0x30) { + diagnostics.append("ASN.1 SEQUENCE Length: ") + .append(signature[1] & 0xFF).append("\n"); + if (signature[2] == 0x02) { + int rLen = signature[3] & 0xFF; + diagnostics.append("ASN.1 R Length: ") + .append(rLen).append("\n"); + if (4 + rLen < signature.length && + signature[4 + rLen] == 0x02) { + int sLen = signature[5 + rLen] & 0xFF; + diagnostics.append("ASN.1 S Length: ") + .append(sLen).append("\n"); + } + } + } + + /* Timing and Thread Information */ + diagnostics.append("Failure Timestamp: ") + .append(System.currentTimeMillis()).append("\n"); + diagnostics.append("Thread ID: ") + .append(Thread.currentThread().getId()).append("\n"); + diagnostics.append("Thread Name: ") + .append(Thread.currentThread().getName()).append("\n"); + + /* All Available Providers */ + diagnostics.append("All Available Providers:\n"); + Provider[] allProviders = Security.getProviders(); + for (Provider p : allProviders) { + diagnostics.append(" ").append(p.getName()) + .append(" v").append(p.getVersion()) + .append(" - ").append(p.getInfo()).append("\n"); + } + + System.err.println(diagnostics.toString()); + fail("Signature verification failed when generating with " + "wolfJCE and verifying with system default JCE " + - "provider"); + "provider. See diagnostics above for " + + "reproduction details."); } } }