From f15afc8f5b6238d10b2562237a4320003f108ba7 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Mon, 17 Feb 2020 14:47:35 -0700 Subject: [PATCH 01/11] register wolfJSSE TrusttManager as PKIX provider --- src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java b/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java index a7db754..0ba96cc 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java @@ -77,6 +77,8 @@ public final class WolfSSLProvider extends Provider { "com.wolfssl.provider.jsse.WolfSSLContext$DEFAULT_Context"); /* Trust Factory */ + put("TrustManagerFactory.PKIX", + "com.wolfssl.provider.jsse.WolfSSLTrustManager"); put("TrustManagerFactory.X509", "com.wolfssl.provider.jsse.WolfSSLTrustManager"); put("TrustManagerFactory.SunX509", From 6b96f5195c3f8335592dc91a0f6b07cbe1adab99 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Mon, 17 Feb 2020 14:48:43 -0700 Subject: [PATCH 02/11] add extra debug messages in SSLContext and TrustX509 --- src/java/com/wolfssl/provider/jsse/WolfSSLContext.java | 3 +++ src/java/com/wolfssl/provider/jsse/WolfSSLTrustX509.java | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java index 01519ca..c0254ed 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java @@ -141,6 +141,9 @@ public class WolfSSLContext extends SSLContextSpi { return; } + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Using X509TrustManager: " + tm.toString()); + X509Certificate[] caList = tm.getAcceptedIssuers(); if (caList == null) { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustX509.java b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustX509.java index 08e7636..7edd84e 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustX509.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustX509.java @@ -129,8 +129,13 @@ public class WolfSSLTrustX509 implements X509TrustManager { @Override public X509Certificate[] getAcceptedIssuers() { - if (CAs != null) + if (CAs != null) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "accepted issuer array size = " + CAs.size()); return CAs.toArray(new X509Certificate[CAs.size()]); + } + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "accepted issuer array is null"); return null; } } From 965fb6a1f857f8c178788546050b89310e19e019 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Mon, 17 Feb 2020 14:49:32 -0700 Subject: [PATCH 03/11] correctly load default system CA certificates if javax.net.ssl.trustStore is set --- .../provider/jsse/WolfSSLTrustManager.java | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java index fcd77e1..a672440 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java @@ -53,6 +53,7 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { String file = System.getProperty("javax.net.ssl.trustStore"); char passAr[] = null; InputStream stream = null; + boolean systemCertsFound = false; try { if (pass != null) { @@ -60,30 +61,46 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { } certs = KeyStore.getInstance("JKS"); if (file == null) { + /* try to load trusted system certs if possible */ String home = System.getenv("JAVA_HOME"); if (home != null) { + if (!home.endsWith("/") && !home.endsWith("\\")) { + /* add trailing slash if not there already */ + home = home.concat("/"); + } + + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "$JAVA_HOME = " + home); + + /* trying: "lib/security/jssecacerts" */ File f = new File(home.concat( - "lib/security/jssecacerts")); + "jre/lib/security/jssecacerts")); if (f.exists()) { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "Loading certs from " + home.concat("lib/security/jssecacerts")); stream = new FileInputStream(f); certs.load(stream, passAr); + stream.close(); + systemCertsFound = true; } - else { - f = new File(home.concat("lib/security/cacerts")); - if (f.exists()) { - WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - "Loading certs from " + - home.concat("lib/security/cacerts")); - stream = new FileInputStream(f); - certs.load(stream, passAr); - } - else { - WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - "Using Anonymous cipher suite"); - } + + /* trying: "lib/security/cacerts" */ + f = new File(home.concat("jre/lib/security/cacerts")); + if (f.exists()) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Loading certs from " + + home.concat("lib/security/cacerts")); + stream = new FileInputStream(f); + certs.load(stream, passAr); + stream.close(); + systemCertsFound = true; + } + + if (systemCertsFound == false) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "No trusted system certs found, " + + "using Anonymous cipher suite"); } } } @@ -92,6 +109,7 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { "Loading certs from " + file); stream = new FileInputStream(file); certs.load(stream, passAr); + stream.close(); } } catch (FileNotFoundException ex) { Logger.getLogger( @@ -110,14 +128,6 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { WolfSSLTrustManager.class.getName()).log( Level.SEVERE, null, ex); } - - if (stream != null) { - try { - stream.close(); - } catch (IOException e) { - throw new KeyStoreException("Unable to close stream"); - } - } } this.store = certs; } From 31189f6264db9c78e40c14f51ee4cf845383e589 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Mon, 17 Feb 2020 16:49:02 -0700 Subject: [PATCH 04/11] add WolfSSLCertificate constructors for PEM arrays and files, DER files --- native/com_wolfssl_WolfSSLCertificate.c | 77 ++++ native/com_wolfssl_WolfSSLCertificate.h | 8 + src/java/com/wolfssl/WolfSSLCertificate.java | 79 +++- .../wolfssl/test/WolfSSLCertificateTest.java | 352 +++++++++++------- 4 files changed, 382 insertions(+), 134 deletions(-) diff --git a/native/com_wolfssl_WolfSSLCertificate.c b/native/com_wolfssl_WolfSSLCertificate.c index 05035b0..86dde3b 100644 --- a/native/com_wolfssl_WolfSSLCertificate.c +++ b/native/com_wolfssl_WolfSSLCertificate.c @@ -64,6 +64,83 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertificate_d2i_1X509 return (jlong)(intptr_t)wolfSSL_d2i_X509(NULL, &pt, sz); } +JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_certPemToDer + (JNIEnv* jenv, jclass jcl, jbyteArray pem, jint pemSz) +{ + unsigned char* der = NULL; + unsigned char* tmpPem = NULL; + int derSz = 0; + jbyteArray ret; + + if (!jenv || !pem || (pemSz < 0)) + return NULL; + + /* find exception class */ + jclass excClass = (*jenv)->FindClass(jenv, + "com/wolfssl/WolfSSLJNIException"); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionDescribe(jenv); + (*jenv)->ExceptionClear(jenv); + return NULL; + } + + /* allocate space for DER, using PEM sz. DER will be smaller than PEM */ + derSz = pemSz; + der = (unsigned char*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) { + return NULL; + } + XMEMSET(der, 0, derSz); + + /* allocate space for converted jbyteArray */ + tmpPem = (unsigned char*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (tmpPem == NULL) { + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + (*jenv)->GetByteArrayRegion(jenv, pem, 0, pemSz, (jbyte*)tmpPem); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionDescribe(jenv); + (*jenv)->ExceptionClear(jenv); + XFREE(tmpPem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + (*jenv)->ThrowNew(jenv, excClass, + "Failed to get byte region in native certPemToDer"); + return NULL; + } + + derSz = wc_CertPemToDer(tmpPem, pemSz, der, derSz, CERT_TYPE); + if (derSz < 0) { + XFREE(tmpPem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + (*jenv)->ThrowNew(jenv, excClass, + "wc_CertPemToDer() failed in native certPemToDer"); + return NULL; + } + XFREE(tmpPem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + ret = (*jenv)->NewByteArray(jenv, derSz); + if (!ret) { + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + (*jenv)->ThrowNew(jenv, jcl, + "Failed to create Java byte array in native certPemToDer"); + return NULL; + } + + (*jenv)->SetByteArrayRegion(jenv, ret, 0, derSz, (jbyte*)der); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionDescribe(jenv); + (*jenv)->ExceptionClear(jenv); + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); + (*jenv)->ThrowNew(jenv, excClass, + "Failed to set byte region in native certPemToDer"); + return NULL; + } + + return ret; +} + JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1der (JNIEnv* jenv, jclass jcl, jlong x509) { diff --git a/native/com_wolfssl_WolfSSLCertificate.h b/native/com_wolfssl_WolfSSLCertificate.h index 6160999..41172ed 100644 --- a/native/com_wolfssl_WolfSSLCertificate.h +++ b/native/com_wolfssl_WolfSSLCertificate.h @@ -15,6 +15,14 @@ extern "C" { JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertificate_d2i_1X509 (JNIEnv *, jclass, jbyteArray, jint); +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: certPemToDer + * Signature: ([BI)[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_certPemToDer + (JNIEnv *, jclass, jbyteArray, jint); + /* * Class: com_wolfssl_WolfSSLCertificate * Method: X509_get_der diff --git a/src/java/com/wolfssl/WolfSSLCertificate.java b/src/java/com/wolfssl/WolfSSLCertificate.java index 042d141..de566ac 100644 --- a/src/java/com/wolfssl/WolfSSLCertificate.java +++ b/src/java/com/wolfssl/WolfSSLCertificate.java @@ -43,6 +43,7 @@ public class WolfSSLCertificate { private long x509Ptr = 0; static native long d2i_X509(byte[] der, int len); + static native byte[] certPemToDer(byte[] pem, int len); static native byte[] X509_get_der(long x509); static native byte[] X509_get_tbs(long x509); static native void X509_free(long x509); @@ -68,7 +69,38 @@ public class WolfSSLCertificate { public WolfSSLCertificate(byte[] der) throws WolfSSLException { x509Ptr = d2i_X509(der, der.length); if (x509Ptr == 0) { - throw new WolfSSLException("Failed to create SSL Context"); + throw new WolfSSLException("Failed to create WolfSSLCertificate"); + } + this.active = true; + } + + public WolfSSLCertificate(byte[] in, int format) throws WolfSSLException { + byte[] input = in; + + if (in == null || in.length == 0) { + throw new WolfSSLException( + "Input array must not be null or zero length"); + } + + if (format != WolfSSL.SSL_FILETYPE_ASN1 && + format != WolfSSL.SSL_FILETYPE_PEM) { + throw new WolfSSLException( + "Input format must be WolfSSL.SSL_FILETYPE_ASN1 or " + + "WolfSSL.SSL_FILETYPE_PEM"); + } + + if (format == WolfSSL.SSL_FILETYPE_PEM) { + /* convert PEM to DER */ + input = certPemToDer(in, in.length); + if (input == null) { + throw new WolfSSLException("Failed to convert PEM to DER"); + } + } + + /* create from DER array */ + x509Ptr = d2i_X509(input, input.length); + if (x509Ptr == 0) { + throw new WolfSSLException("Failed to create WolfSSLCertificate"); } this.active = true; } @@ -88,6 +120,51 @@ public class WolfSSLCertificate { "Failed to create WolfSSLCertificate", ex); } + x509Ptr = d2i_X509(der, der.length); + if (x509Ptr == 0) { + throw new WolfSSLException( + "Failed to create WolfSSLCertificate, d2i_X509() returned 0"); + } + this.active = true; + } + + public WolfSSLCertificate(String fileName, int format) + throws WolfSSLException { + InputStream stream = null; + byte[] bytes = null; + byte[] der = null; + + if (fileName == null) { + throw new WolfSSLException("Input file must not be null"); + } + + if (format != WolfSSL.SSL_FILETYPE_ASN1 && + format != WolfSSL.SSL_FILETYPE_PEM) { + throw new WolfSSLException( + "Input format must be WolfSSL.SSL_FILETYPE_ASN1 or " + + "WolfSSL.SSL_FILETYPE_PEM"); + } + + File f = new File(fileName); + try { + bytes = new byte[(int) f.length()]; + stream = new FileInputStream(f); + stream.read(bytes, 0, bytes.length); + stream.close(); + } catch (IOException ex) { + throw new WolfSSLException( + "Failed to create WolfSSLCertificate", ex); + } + + if (format == WolfSSL.SSL_FILETYPE_PEM) { + /* convert PEM to DER */ + der = certPemToDer(bytes, bytes.length); + if (der == null) { + throw new WolfSSLException("Failed to convert PEM to DER"); + } + } else { + der = bytes; + } x509Ptr = d2i_X509(der, der.length); if (x509Ptr == 0) { diff --git a/src/test/com/wolfssl/test/WolfSSLCertificateTest.java b/src/test/com/wolfssl/test/WolfSSLCertificateTest.java index e34511f..e997b07 100644 --- a/src/test/com/wolfssl/test/WolfSSLCertificateTest.java +++ b/src/test/com/wolfssl/test/WolfSSLCertificateTest.java @@ -33,6 +33,7 @@ import java.util.logging.Logger; import static org.junit.Assert.fail; import org.junit.Test; +import com.wolfssl.WolfSSL; import com.wolfssl.WolfSSLCertificate; import com.wolfssl.WolfSSLException; @@ -44,7 +45,8 @@ public class WolfSSLCertificateTest { public final static int TEST_FAIL = -1; public final static int TEST_SUCCESS = 0; - public static String cliCert = "examples/certs/client-cert.der"; + public static String cliCertDer = "examples/certs/client-cert.der"; + public static String cliCertPem = "examples/certs/client-cert.pem"; public static String external = "examples/certs/ca-google-root.der"; public static String bogusFile = "/dev/null"; private WolfSSLCertificate cert; @@ -54,10 +56,29 @@ public class WolfSSLCertificateTest { System.out.println("WolfSSLCertificate Class"); - cliCert = WolfSSLTestCommon.getPath(cliCert); - external = WolfSSLTestCommon.getPath(external); - - test_WolfSSLCertificate_new(); + cliCertDer = WolfSSLTestCommon.getPath(cliCertDer); + cliCertPem = WolfSSLTestCommon.getPath(cliCertPem); + external = WolfSSLTestCommon.getPath(external); + + /* WolfSSLCertificate(byte[] der) */ + test_WolfSSLCertificate_new_derArray(); + test_runCertTestsAfterConstructor(); + + /* WolfSSLCertificate(String der) */ + test_WolfSSLCertificate_new_pemArray(); + test_runCertTestsAfterConstructor(); + + /* WolfSSLCertificate(byte[] pem) */ + test_WolfSSLCertificate_new_derFile(); + test_runCertTestsAfterConstructor(); + + /* WolfSSLCertificate(String pem) */ + test_WolfSSLCertificate_new_pemFile(); + test_runCertTestsAfterConstructor(); + } + + + public void test_runCertTestsAfterConstructor() { test_getSerial(); test_notBefore(); test_notAfter(); @@ -77,89 +98,154 @@ public class WolfSSLCertificateTest { test_toString(); test_free(); } - - - public void test_WolfSSLCertificate_new() { - File f = new File(cliCert); + + + public void test_WolfSSLCertificate_new_derArray() { + File f = new File(cliCertDer); byte[] der = null; - System.out.print("\tWolfSSLCertificate_new"); + System.out.print("\tnew(byte[] der)"); + try { InputStream stream = new FileInputStream(f); der = new byte[(int) f.length()]; stream.read(der, 0, der.length); stream.close(); } catch (IOException ex) { - System.out.println("\t\t... failed"); - fail("Unable to read file " + cliCert); - Logger.getLogger(WolfSSLCertificateTest.class.getName()).log(Level.SEVERE, null, ex); + System.out.println("\t\t\t... failed"); + fail("Unable to read file " + cliCertDer); + Logger.getLogger(WolfSSLCertificateTest.class.getName()).log( + Level.SEVERE, null, ex); } - try { this.cert = new WolfSSLCertificate(der); } catch (WolfSSLException ex) { - System.out.println("\t\t... failed"); + System.out.println("\t\t\t... failed"); fail("Unable to initialize class"); - Logger.getLogger(WolfSSLCertificateTest.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(WolfSSLCertificateTest.class.getName()).log( + Level.SEVERE, null, ex); } - System.out.println("\t\t... passed"); + System.out.println("\t\t\t... passed"); } - + + + public void test_WolfSSLCertificate_new_derFile() { + System.out.print("\tnew(String der, int format)"); + + try { + this.cert = new WolfSSLCertificate(cliCertDer, + WolfSSL.SSL_FILETYPE_ASN1); + } catch (WolfSSLException ex) { + System.out.println("\t... failed"); + fail("Unable to initialize class"); + Logger.getLogger(WolfSSLCertificateTest.class.getName()).log( + Level.SEVERE, null, ex); + } + System.out.println("\t... passed"); + } + + + public void test_WolfSSLCertificate_new_pemArray() { + File f = new File(cliCertPem); + byte[] pem = null; + + System.out.print("\tnew(byte[] in, int format)"); + + try { + InputStream stream = new FileInputStream(f); + pem = new byte[(int) f.length()]; + stream.read(pem, 0, pem.length); + stream.close(); + } catch (IOException ex) { + System.out.println("\t... failed"); + fail("Unable to read file " + cliCertPem); + Logger.getLogger(WolfSSLCertificateTest.class.getName()).log( + Level.SEVERE, null, ex); + } + + try { + this.cert = new WolfSSLCertificate(pem, WolfSSL.SSL_FILETYPE_PEM); + } catch (WolfSSLException ex) { + System.out.println("\t... failed"); + fail("Unable to initialize class"); + Logger.getLogger(WolfSSLCertificateTest.class.getName()).log( + Level.SEVERE, null, ex); + } + System.out.println("\t... passed"); + } + + + public void test_WolfSSLCertificate_new_pemFile() { + System.out.print("\tnew(String pem, int format)"); + + try { + this.cert = new WolfSSLCertificate(cliCertPem, + WolfSSL.SSL_FILETYPE_PEM); + } catch (WolfSSLException ex) { + System.out.println("\t... failed"); + fail("Unable to initialize class"); + Logger.getLogger(WolfSSLCertificateTest.class.getName()).log( + Level.SEVERE, null, ex); + } + System.out.println("\t... passed"); + } + + public void test_getSerial() { byte[] expected = new byte[]{(byte)0xaa, (byte)0xc4, (byte)0xbf, (byte)0x4c, (byte)0x50, (byte)0xbd, (byte)0x55, (byte)0x77}; byte[] serial; int i; BigInteger bigi = cert.getSerial(); - - System.out.print("\tgetSerial"); + + System.out.print("\t\tgetSerial"); serial = bigi.toByteArray(); for (i = 0; i < serial.length && i < expected.length; i++) { if (serial[i] != expected[i]) { - System.out.println("\t\t\t... failed"); + System.out.println("\t\t... failed"); fail("Unexpected serial number"); } } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - + @SuppressWarnings("deprecation") public void test_notBefore() { Date date = cert.notBefore(); Date expected = new Date("Fri Apr 13 09:23:09 MDT 2018"); - System.out.print("\tnotBefore"); + System.out.print("\t\tnotBefore"); if (date.compareTo(expected) != 0) { - System.out.println("\t\t\t... failed"); + System.out.println("\t\t... failed"); fail("Unexpected not before date"); } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - - + + @SuppressWarnings("deprecation") public void test_notAfter() { Date date = cert.notAfter(); Date expected = new Date("Thu Jan 07 08:23:09 MST 2021"); - System.out.print("\tnotAfter"); + System.out.print("\t\tnotAfter"); if (date.compareTo(expected) != 0) { - System.out.println("\t\t\t... failed"); + System.out.println("\t\t... failed"); fail("Unexpected not after date"); } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - + public void test_getVersion() { int version = cert.getVersion(); - - System.out.print("\tgetVersion"); + + System.out.print("\t\tgetVersion"); if (version != 3) { - System.out.println("\t\t\t... failed"); + System.out.println("\t\t... failed"); fail("Unexpected version number"); } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - + public void test_getSignature() { byte[] sig = cert.getSignature(); byte[] expected = new byte[] { @@ -217,47 +303,47 @@ public class WolfSSLCertificateTest { (byte)0xB4 }; int i; - System.out.print("\tgetSignature"); + System.out.print("\t\tgetSignature"); for (i = 0; i < sig.length && i < expected.length; i++) { if (sig[i] != expected[i]) { - System.out.println("\t\t\t... failed"); - fail("Unexpected signature"); + System.out.println("\t\t... failed"); + fail("Unexpected signature"); } } + System.out.println("\t\t... passed"); + } + + public void test_isCA() { + System.out.print("\t\tisCA"); + if (this.cert.isCA() != 1) { + System.out.println("\t\t\t... failed"); + fail("Expected isCA to be set"); + } System.out.println("\t\t\t... passed"); } - - public void test_isCA() { - System.out.print("\tisCA"); - if (this.cert.isCA() != 1) { - System.out.println("\t\t\t\t... failed"); - fail("Expected isCA to be set"); - } - System.out.println("\t\t\t\t... passed"); - } - + public void test_getSubject() { String expected = "/C=US/ST=Montana/L=Bozeman/O=wolfSSL_2048/OU=Programming-2048/CN=www.wolfssl.com/emailAddress=info@wolfssl.com"; - - System.out.print("\tgetSubject"); + + System.out.print("\t\tgetSubject"); if (!cert.getSubject().equals(expected)) { - System.out.println("\t\t\t... failed"); - fail("Unexpected subject"); + System.out.println("\t\t... failed"); + fail("Unexpected subject"); } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - + public void test_getIssuer() { String expected = "/C=US/ST=Montana/L=Bozeman/O=wolfSSL_2048/OU=Programming-2048/CN=www.wolfssl.com/emailAddress=info@wolfssl.com"; - - System.out.print("\tgetIssuer"); + + System.out.print("\t\tgetIssuer"); if (!cert.getIssuer().equals(expected)) { - System.out.println("\t\t\t... failed"); - fail("Unexpected issuer"); + System.out.println("\t\t... failed"); + fail("Unexpected issuer"); } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - + public void test_getPubkey() { byte[] expected = new byte[] { (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x22, @@ -331,147 +417,147 @@ public class WolfSSLCertificateTest { }; int i; byte[] pub; - - System.out.print("\tgetPubkey"); + + System.out.print("\t\tgetPubkey"); pub = cert.getPubkey(); for (i = 0; i < pub.length && i < expected.length; i++) { if (pub[i] != expected[i]) { - System.out.println("\t\t\t... failed"); + System.out.println("\t\t... failed"); fail("Unexpected public key value"); } } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - + public void test_getPubkeyType() { String expected = "RSA"; - System.out.print("\tgetPubkeyType"); + System.out.print("\t\tgetPubkeyType"); if (!expected.equals(this.cert.getPubkeyType())) { - System.out.println("\t\t\t... failed"); - fail("Unexpected public key type value"); - } - System.out.println("\t\t\t... passed"); - } - - public void test_getPathLen() { - int expected = -1; - System.out.print("\tgetPathLen"); - if (this.cert.getPathLen() != expected) { - System.out.println("\t\t\t... failed"); - fail("Unexpected path length value"); - } - System.out.println("\t\t\t... passed"); - } - - public void test_getSignatureType() { - String expected = "SHA256withRSA"; - System.out.print("\tgetSignatureType"); - if (!expected.equals(this.cert.getSignatureType())) { System.out.println("\t\t... failed"); - fail("Unexpected signature type"); + fail("Unexpected public key type value"); } System.out.println("\t\t... passed"); } - + + public void test_getPathLen() { + int expected = -1; + System.out.print("\t\tgetPathLen"); + if (this.cert.getPathLen() != expected) { + System.out.println("\t\t... failed"); + fail("Unexpected path length value"); + } + System.out.println("\t\t... passed"); + } + + public void test_getSignatureType() { + String expected = "SHA256withRSA"; + System.out.print("\t\tgetSignatureType"); + if (!expected.equals(this.cert.getSignatureType())) { + System.out.println("\t... failed"); + fail("Unexpected signature type"); + } + System.out.println("\t... passed"); + } + public void test_verify() { byte[] pubkey; - - System.out.print("\tverify"); + + System.out.print("\t\tverify"); pubkey = this.cert.getPubkey(); if (pubkey == null) { - System.out.println("\t\t\t\t... failed"); + System.out.println("\t\t\t... failed"); fail("Could not get public key"); return; } - + if (this.cert.verify(pubkey, pubkey.length) != true) { - System.out.println("\t\t\t\t... failed"); - fail("Verify signature failed"); + System.out.println("\t\t\t... failed"); + fail("Verify signature failed"); } - System.out.println("\t\t\t\t... passed"); + System.out.println("\t\t\t... passed"); } - + public void test_getSignatureOID() { - System.out.print("\tgetSignatureOID"); - + System.out.print("\t\tgetSignatureOID"); + /* make sure is sha256WithRSAEncryption OID */ if (!this.cert.getSignatureOID().equals("1.2.840.113549.1.1.11")) { - System.out.println("\t\t\t... failed"); - fail("Could not get public key"); + System.out.println("\t\t... failed"); + fail("Could not get public key"); } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - + public void test_getKeyUsage() { WolfSSLCertificate ext; boolean[] expected = { false, false, false, false, false, true, true, false, false }; - - System.out.print("\tgetKeyUsage"); + + System.out.print("\t\tgetKeyUsage"); if (this.cert.getKeyUsage() != null) { - System.out.println("\t\t\t... failed"); - fail("Found key usage extension when not expecting any"); + System.out.println("\t\t... failed"); + fail("Found key usage extension when not expecting any"); } - + /* test with certificate that has key usage extension */ try { int i; boolean[] kuse; - + ext = new WolfSSLCertificate(this.external); kuse = ext.getKeyUsage(); if (kuse == null) { - System.out.println("\t\t\t... failed"); + System.out.println("\t\t... failed"); fail("Did not find key usage extension"); return; } - + for (i = 0; i < kuse.length; i++) { if (kuse[i] != expected[i]) { - System.out.println("\t\t\t... failed"); - fail("Found wrong key usage extension"); + System.out.println("\t\t... failed"); + fail("Found wrong key usage extension"); } } ext.free(); } catch (WolfSSLException ex) { Logger.getLogger(WolfSSLCertificateTest.class.getName()).log(Level.SEVERE, null, ex); - System.out.println("\t\t\t... failed"); - fail("Error loading external certificate"); + System.out.println("\t\t... failed"); + fail("Error loading external certificate"); } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - + public void test_getExtensionSet() { - System.out.print("\tgetExtensionSet"); - + System.out.print("\t\tgetExtensionSet"); + if (this.cert.getExtensionSet("2.5.29.19") != 1) { - System.out.println("\t\t\t... failed"); + System.out.println("\t\t... failed"); fail("Error with basic constraint extension"); } - + if (this.cert.getExtensionSet("2.5.29.14") != 1) { - System.out.println("\t\t\t... failed"); + System.out.println("\t\t... failed"); fail("Error with subject key ID extension"); } - System.out.println("\t\t\t... passed"); + System.out.println("\t\t... passed"); } - + public void test_toString() { String s; - System.out.print("\ttoString"); + System.out.print("\t\ttoString"); s = cert.toString(); if (s == null) { - System.out.println("\t\t\t... failed"); + System.out.println("\t\t... failed"); fail("Error getting certificate string"); } + System.out.println("\t\t... passed"); + } + + public void test_free() { + System.out.print("\t\tfree"); + this.cert.free(); System.out.println("\t\t\t... passed"); } - - public void test_free() { - System.out.print("\tfree"); - this.cert.free(); - System.out.println("\t\t\t\t... passed"); - } } From c22efee7884a0e2043c32f17358f1a7ee2c6d762 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Mon, 17 Feb 2020 16:53:11 -0700 Subject: [PATCH 05/11] load Android trusted system certs by default if available --- .../provider/jsse/WolfSSLTrustManager.java | 61 +++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java index a672440..ea91159 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java @@ -26,16 +26,22 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.ByteArrayInputStream; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; import java.util.logging.Level; import java.util.logging.Logger; import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactorySpi; +import com.wolfssl.WolfSSL; +import com.wolfssl.WolfSSLCertificate; +import com.wolfssl.WolfSSLException; /** * wolfSSL implemenation of TrustManagerFactorySpi @@ -54,6 +60,7 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { char passAr[] = null; InputStream stream = null; boolean systemCertsFound = false; + int aliasCnt = 0; try { if (pass != null) { @@ -96,12 +103,58 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { stream.close(); systemCertsFound = true; } + } - if (systemCertsFound == false) { - WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - "No trusted system certs found, " + - "using Anonymous cipher suite"); + /* ANDROID, detect based on ANDROID_ROOT */ + home = System.getenv("ANDROID_ROOT"); + if (home != null) { + /* try: "/system/security/cacerts/*" + * this is a directory of individual PEM files */ + + if (!home.endsWith("/") && !home.endsWith("\\")) { + /* add trailing slash if not there already */ + home = home.concat("/"); } + + File cadir = + new File(home.concat("etc/security/cacerts")); + String[] cafiles = cadir.list(); + + /* get factory for cert creation */ + CertificateFactory cfactory = + CertificateFactory.getInstance("X.509"); + + /* loop over all PEM certs */ + for (String cafile : cafiles) { + + WolfSSLCertificate certPem; + try { + certPem = new WolfSSLCertificate( + cafile, WolfSSL.SSL_FILETYPE_PEM); + } catch (WolfSSLException we) { + /* skip, error parsing PEM */ + continue; + } + + /* convert DER arry to Certificate */ + Certificate tmpCert = + cfactory.generateCertificate( + new ByteArrayInputStream( + certPem.getDer())); + + /* import into KeyStore */ + certs.setCertificateEntry( + "alias"+aliasCnt, tmpCert); + + /* increment alias counter for unique aliases */ + aliasCnt++; + } + } + + if (systemCertsFound == false) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "No trusted system certs found, " + + "using Anonymous cipher suite"); } } else { From 93b84e31d97c85472767bae36bf5edef5cf0fd0a Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Tue, 25 Feb 2020 17:18:03 -0700 Subject: [PATCH 06/11] add X509Certificate.getSubjectAlternativeNames() support --- native/com_wolfssl_WolfSSLCertificate.c | 27 ++++++++++ native/com_wolfssl_WolfSSLCertificate.h | 8 +++ src/java/com/wolfssl/WolfSSLCertificate.java | 51 +++++++++++++++++++ .../wolfssl/provider/jsse/WolfSSLX509.java | 9 ++++ 4 files changed, 95 insertions(+) diff --git a/native/com_wolfssl_WolfSSLCertificate.c b/native/com_wolfssl_WolfSSLCertificate.c index 86dde3b..d072962 100644 --- a/native/com_wolfssl_WolfSSLCertificate.c +++ b/native/com_wolfssl_WolfSSLCertificate.c @@ -765,3 +765,30 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1is_1extension_1 return 0; } +JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1next_1altname + (JNIEnv* jenv, jclass jcl, jlong x509) +{ +#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS) + char* altname; + jstring retString; + (void)jcl; + + if (!jenv || !x509) + return NULL; + + altname = wolfSSL_X509_get_next_altname((WOLFSSL_X509*)(intptr_t)x509); + if (altname == NULL) { + return NULL; + } + retString = (*jenv)->NewStringUTF(jenv, altname); + return retString; + +#else + (void)jenv; + (void)jcl; + (void)ssl; + (void)x509; + return NULL; +#endif +} + diff --git a/native/com_wolfssl_WolfSSLCertificate.h b/native/com_wolfssl_WolfSSLCertificate.h index 41172ed..9cf2511 100644 --- a/native/com_wolfssl_WolfSSLCertificate.h +++ b/native/com_wolfssl_WolfSSLCertificate.h @@ -191,6 +191,14 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1exte JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1is_1extension_1set (JNIEnv *, jclass, jlong, jstring); +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_get_next_altname + * Signature: (J)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1next_1altname + (JNIEnv *, jclass, jlong); + #ifdef __cplusplus } #endif diff --git a/src/java/com/wolfssl/WolfSSLCertificate.java b/src/java/com/wolfssl/WolfSSLCertificate.java index de566ac..68a1266 100644 --- a/src/java/com/wolfssl/WolfSSLCertificate.java +++ b/src/java/com/wolfssl/WolfSSLCertificate.java @@ -30,6 +30,10 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; +import java.util.List; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.logging.Level; import java.util.logging.Logger; @@ -42,6 +46,9 @@ public class WolfSSLCertificate { private boolean active = false; private long x509Ptr = 0; + /* cache alt names once retrieved once */ + private Collection> altNames = null; + static native long d2i_X509(byte[] der, int len); static native byte[] certPemToDer(byte[] pem, int len); static native byte[] X509_get_der(long x509); @@ -65,6 +72,7 @@ public class WolfSSLCertificate { static native boolean[] X509_get_key_usage(long x509); static native byte[] X509_get_extension(long x509, String oid); static native int X509_is_extension_set(long x509, String oid); + static native String X509_get_next_altname(long x509); public WolfSSLCertificate(byte[] der) throws WolfSSLException { x509Ptr = d2i_X509(der, der.length); @@ -302,6 +310,49 @@ public class WolfSSLCertificate { return X509_is_extension_set(this.x509Ptr, oid); } + /** + * Returns an immutable Collection of subject alternative names from this + * certificate's SubjectAltName extension. + * + * Each collection item is a List containing two objects: + * [0] = Integer representing type of name, 0-8 (ex: 2 == dNSName) + * [1] = String representing altname entry. + * + * Note: this currently returns all altNames as dNSName types, with the + * second list element being a String. + * + * @returns immutable Collection of subject alternative names, or null + */ + public Collection> getSubjectAltNames() { + + if (this.active == false) { + throw new IllegalStateException("Object has been freed"); + } + + if (this.altNames != null) { + /* already gathered, return cached version */ + return this.altNames; + } + + Collection> names = new ArrayList>(); + + String nextAltName = X509_get_next_altname(this.x509Ptr); + while (nextAltName != null) { + Object[] entry = new Object[2]; + entry[0] = 2; // Only return dNSName type for now + entry[1] = nextAltName; + List entryList = Arrays.asList(entry); + + names.add(Collections.unmodifiableList(entryList)); + nextAltName = X509_get_next_altname(this.x509Ptr); + } + + /* cache altNames collection for later use */ + this.altNames = Collections.unmodifiableCollection(names); + + return this.altNames; + } + /** * Returns X509Certificate object based on this certificate. * diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java b/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java index 527f8df..9152cb9 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java @@ -34,11 +34,14 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Date; import java.util.Set; import java.util.TreeSet; +import java.util.List; +import java.util.Collection; import com.wolfssl.WolfSSLCertificate; import com.wolfssl.WolfSSLException; @@ -187,6 +190,12 @@ public class WolfSSLX509 extends X509Certificate { return ret; } + @Override + public Collection> getSubjectAlternativeNames() + throws CertificateParsingException { + return this.cert.getSubjectAltNames(); + } + @Override public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, From 0006e5dc48f789caeeac615df0057ade274a4c46 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 26 Feb 2020 12:07:30 -0700 Subject: [PATCH 07/11] add test case for X509Certificate.getSubjectAlternativeNames() --- examples/certs/example.der | Bin 0 -> 1860 bytes src/java/com/wolfssl/WolfSSLCertificate.java | 2 +- .../jsse/test/WolfSSLTestFactory.java | 3 + .../provider/jsse/test/WolfSSLX509Test.java | 76 ++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 examples/certs/example.der diff --git a/examples/certs/example.der b/examples/certs/example.der new file mode 100644 index 0000000000000000000000000000000000000000..39a521369f4a19781908ba35f14f0ce48145f543 GIT binary patch literal 1860 zcmah~X;c$e6rPz(0)(BgNf8FC1w`Nt2y##>5Wqk|@k9_8ln{mx2ua975NMSk!G%S! zb!kBYC|Jtj;8u%>m=+_q*S{_q}%qsPzJX zn&G0QAuxiNnRaCMa-LPSM4GyNpBnEs42&5D(={B;YhxHTq(dMQHv|R@S~SXFA<Eu3G~9a1Yap5$d4?8kYVgV;9z5n`{B5k zA9y#G*%*5P+zWV-lN`%H?w*N!EMQJK)@L!rgcynXt!Z9ePWWuvbgXL|H7mat*cvY_oaHHb9>TDt%9r?^-42vi#Z2PmlURxzFJUc6!6bG|?=zOT>wJ zIXbgf+C53BT<)pv$N9gc(FYQ1PnkR{xzV=op?k84)x5r&J%2kTx<3)Rp_$z(;`HJ- z2n~kdYBfy<)U+1hNLF$3rzly@wU(x9dG>0YcgfS`Zc(V;!5KGBcHIP%DFYMK8nsN? zk%0VZu%))^mhVu;$;Q^owAy1JH<#KsN3%et`rk*PHXJ(_z9j8~KqM+Z2;^P(Adts5 z(Fui{;FZEoP>^_FLWN)o!y_n4L+IMkkf)*6z>=Zw#(?Q`JsLc|LO?2I?uaIW1mLN4 z*Scw3lNAc7zo#c(Ci3=3Bp(l-d^{c`x2Igr=ef(1d0y@UUk`Hozkr$l1Bjr=Ff;_P z!7PSByoLj7-ilxtOb0GwAtA7}Jr#kR41v1L6Cz+oae+RAA;>i%TLQ=#!@w{q1!6FD zOa`#V_I(x-zFa!N2M8UvLNxwkx$>walF2K85tR#zsxtzp z_q2w=B+HA!mscYwf~sK&Ia6UFq=I%g8Eigi8*5q6%&IygkTU1^>_Fdqa{Z@Us&A?DB=XIOUym&GTLRB~Ko$sS8=yY7$yJEPea7I4B6pfC`kYcbDc26tZ`&YIz|Z zi7A>N<2w?5C|-B)!N^K&p6Mv@Hmi5U^FauLN$OM=>}$V1&Ug1Xpy>_V6tL0Gb4^2% zZtE(!BWG)rImvtBO*uzHchGJRo@O}b!P!B#NjbSA&e^-VV}IhXSj z($$^N?nPE3Dl2>QE<^{pGK%)=e>9pS%d3 zUHE9&()i1Y!+h5YcLa-6E$az`!(S$&`MioNMVJvjsOx;0&Rl*u=Jebdvciws9Qi{a z+Z+tZrTI?-0&7#)mom$;qd9kurtZ`n88W7A${aTDchwrT3oQ*#qM7^8_7_}&%iES_ zr4RRucj>f^TihKV%#A+bO*d-S`Peq5Bqv3*#yDMD-oWQ)*0%FmLUv7cMZ;d9jGs$1 zsPn21ZQuAEwrIp|9xuRw(~;`;=Ek7SRaN-> getSubjectAltNames() { diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java index 8453fec..c70e0e5 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java @@ -65,6 +65,7 @@ class WolfSSLTestFactory { protected String caJKS; protected String rsaJKS; protected String googleCACert; + protected String exampleCert; protected final static char[] jksPass = "wolfSSL test".toCharArray(); protected String keyStoreType = "JKS"; private boolean extraDebug = false; @@ -77,6 +78,7 @@ class WolfSSLTestFactory { caJKS = "examples/provider/cacerts.jks"; rsaJKS = "examples/provider/rsa.jks"; googleCACert = "examples/certs/ca-google-root.der"; + exampleCert = "examples/certs/example.der"; /* test if running from IDE directory */ File f = new File(serverJKS); @@ -104,6 +106,7 @@ class WolfSSLTestFactory { caJKS = in.concat(caJKS); rsaJKS = in.concat(rsaJKS); googleCACert = in.concat(googleCACert); + exampleCert = in.concat(exampleCert); } private boolean isIDEFile() { diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java index 0dd8ac2..b00dd15 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java @@ -43,6 +43,9 @@ import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.Date; import java.util.Set; +import java.util.List; +import java.util.ArrayList; +import java.util.Collection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; @@ -545,6 +548,79 @@ public class WolfSSLX509Test { pass("\t\t... passed"); } + @Test + public void testSubjectAlternativeNames() { + + X509Certificate x509; + int ALT_DNS_NAME = 2; /* dNSName type */ + + System.out.print("\tTesting getting alt names"); + + /* populate known alt name list for example.com cert, for comparison */ + List expected = new ArrayList<>(); + expected.add("www.example.net"); + expected.add("www.example.edu"); + expected.add("www.example.com"); + expected.add("example.org"); + expected.add("example.net"); + expected.add("example.edu"); + expected.add("example.com"); + expected.add("www.example.org"); + + /* list to hold found altNames */ + List found = new ArrayList<>(); + + try { + x509 = new WolfSSLX509(tf.exampleCert); + + Collection subjectAltNames = x509.getSubjectAlternativeNames(); + if (subjectAltNames == null) { + error("\t... failed"); + fail("subjectAltNames Collection was null"); + } + + for (Object subjectAltName : subjectAltNames) { + List entry = (List)subjectAltName; + if (entry == null || entry.size() < 2) { + error("\t... failed"); + fail("subjectAltName List null or length < 2"); + } + Integer altNameType = (Integer)entry.get(0); + if (altNameType == null) { + error("\t... failed"); + fail("subjectAltName List[0] was null, should be Integer"); + } + if (altNameType != ALT_DNS_NAME) { + error("\t... failed"); + fail("subjectAltName type is not ALT_DNS_NAME (2)"); + } + String altName = (String)entry.get(1); + if (altName == null) { + error("\t... failed"); + fail("Individual altName was null, should not be"); + } + found.add(altName); + } + + if (found.size() != expected.size()) { + error("\r... failed"); + fail("altName list size differs from expected size"); + } + + for (int i = 0; i < found.size(); i++) { + if (!found.get(i).equals(expected.get(i))) { + error("\r... failed"); + fail("altName entry does not match expected: found: " + + found.get(i) + ", expected: " + expected.get(i)); + } + } + + } catch (Exception ex) { + error("\t... failed"); + fail("unexpected exception found"); + } + pass("\t... passed"); + } private void pass(String msg) { WolfSSLTestFactory.pass(msg); From 9f8fbdcab3104c675b67cd658f8d027df26650b8 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 26 Feb 2020 12:36:22 -0700 Subject: [PATCH 08/11] adjust Android default CA cert loading in TrustManager --- .../provider/jsse/WolfSSLTrustManager.java | 91 ++++++++++++++++--- 1 file changed, 78 insertions(+), 13 deletions(-) diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java index ea91159..f60e383 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java @@ -57,16 +57,50 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { if (in == null) { String pass = System.getProperty("javax.net.ssl.trustStorePassword"); String file = System.getProperty("javax.net.ssl.trustStore"); + String type = System.getProperty("javax.net.ssl.trustStoreType"); + String vmVendor = System.getProperty("java.vm.vendor"); char passAr[] = null; InputStream stream = null; boolean systemCertsFound = false; int aliasCnt = 0; + String[] cafiles = null; try { if (pass != null) { passAr = pass.toCharArray(); } - certs = KeyStore.getInstance("JKS"); + + /* default to JKS KeyStore type if not set at system level */ + try { + if (type != null && type != "") { + certs = KeyStore.getInstance(type); + } else { + if (vmVendor.equals("The Android Project")) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Detected Android VM, using BKS KeyStore type"); + certs = KeyStore.getInstance("BKS"); + } else { + certs = KeyStore.getInstance("JKS"); + } + } + } catch (KeyStoreException kse) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, + "Unsupported KeyStore type: " + type); + throw kse; + } + + try { + /* initialize KeyStore, loading certs below will + * overwrite if needed, otherwise Android needs + * this to be initialized here */ + certs.load(null, null); + + } catch (Exception e) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, + "Error initializing KeyStore with load(null, null)"); + throw e; + } + if (file == null) { /* try to load trusted system certs if possible */ String home = System.getenv("JAVA_HOME"); @@ -116,9 +150,20 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { home = home.concat("/"); } - File cadir = - new File(home.concat("etc/security/cacerts")); - String[] cafiles = cadir.list(); + String caStoreDir = home.concat("etc/security/cacerts"); + File cadir = new File(caStoreDir); + try { + cafiles = cadir.list(); + } catch (Exception e) { + /* denied access reading cacerts directory */ + WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, + "Permission error when trying to read " + + "system CA certificates"); + throw e; + } + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Found " + cafiles.length + " CA files to load " + + "into KeyStore"); /* get factory for cert creation */ CertificateFactory cfactory = @@ -128,27 +173,47 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { for (String cafile : cafiles) { WolfSSLCertificate certPem; + String fullCertPath = caStoreDir.concat("/"); + fullCertPath = fullCertPath.concat(cafile); + try { certPem = new WolfSSLCertificate( - cafile, WolfSSL.SSL_FILETYPE_PEM); + fullCertPath, WolfSSL.SSL_FILETYPE_PEM); } catch (WolfSSLException we) { /* skip, error parsing PEM */ + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Skipped loading cert: " + fullCertPath); continue; } - /* convert DER arry to Certificate */ - Certificate tmpCert = - cfactory.generateCertificate( - new ByteArrayInputStream( - certPem.getDer())); + byte[] derArray = certPem.getDer(); + ByteArrayInputStream bis = + new ByteArrayInputStream(derArray); + Certificate tmpCert = null; - /* import into KeyStore */ - certs.setCertificateEntry( - "alias"+aliasCnt, tmpCert); + try { + tmpCert = cfactory.generateCertificate(bis); + } catch (CertificateException ce) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, + "Error generating certificate from " + + "ByteArrayInputStream"); + throw ce; + } + + String aliasString = "alias" + aliasCnt; + try { + certs.setCertificateEntry(aliasString, tmpCert); + } catch (KeyStoreException kse) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, + "Error setting certificate entry in " + + "KeyStore, skipping loading cert"); + continue; + } /* increment alias counter for unique aliases */ aliasCnt++; } + systemCertsFound = true; } if (systemCertsFound == false) { From d1ecce7051893ac13119b0340e8a49fc6dbe094c Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 26 Feb 2020 13:21:32 -0700 Subject: [PATCH 09/11] update README placeholder with new items --- README | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README b/README index a20a97c..3c8cba5 100644 --- a/README +++ b/README @@ -24,6 +24,10 @@ wolfSSL JNI Release X.X.X (TBD) Release X.X.X has bug fixes and new features including: - Support for custom TrustManager checkClientTrusted(), checkServerTrusted() +- wolfJSSE TrustManager registered as PKIX provider +- Improved support for auto-loading system CA certificates +- Improved Android TrustManager support +- Support for X509Certificate.getSubjectAlternativeNames() The wolfSSL JNI Manual is available at: http://www.wolfssl.com/documentation/wolfSSL-JNI-Manual.pdf. For build From f78612dee920a59e0f1b87dce6b92f7d7c5a9569 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 26 Feb 2020 14:39:15 -0700 Subject: [PATCH 10/11] free der array in WolfSSLCertificate.c --- native/com_wolfssl_WolfSSLCertificate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/com_wolfssl_WolfSSLCertificate.c b/native/com_wolfssl_WolfSSLCertificate.c index d072962..545911f 100644 --- a/native/com_wolfssl_WolfSSLCertificate.c +++ b/native/com_wolfssl_WolfSSLCertificate.c @@ -137,6 +137,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_certPemToDer "Failed to set byte region in native certPemToDer"); return NULL; } + XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } @@ -786,7 +787,6 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1next_1a #else (void)jenv; (void)jcl; - (void)ssl; (void)x509; return NULL; #endif From 79a1c5484a1d2440d05f532ae839951c4c312c5c Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 26 Feb 2020 14:40:06 -0700 Subject: [PATCH 11/11] rename example.com peer cert to example-com.der --- examples/certs/{example.der => example-com.der} | Bin .../provider/jsse/test/WolfSSLTestFactory.java | 6 +++--- .../wolfssl/provider/jsse/test/WolfSSLX509Test.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename examples/certs/{example.der => example-com.der} (100%) diff --git a/examples/certs/example.der b/examples/certs/example-com.der similarity index 100% rename from examples/certs/example.der rename to examples/certs/example-com.der diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java index c70e0e5..066858f 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java @@ -65,7 +65,7 @@ class WolfSSLTestFactory { protected String caJKS; protected String rsaJKS; protected String googleCACert; - protected String exampleCert; + protected String exampleComCert; protected final static char[] jksPass = "wolfSSL test".toCharArray(); protected String keyStoreType = "JKS"; private boolean extraDebug = false; @@ -78,7 +78,7 @@ class WolfSSLTestFactory { caJKS = "examples/provider/cacerts.jks"; rsaJKS = "examples/provider/rsa.jks"; googleCACert = "examples/certs/ca-google-root.der"; - exampleCert = "examples/certs/example.der"; + exampleComCert = "examples/certs/example-com.der"; /* test if running from IDE directory */ File f = new File(serverJKS); @@ -106,7 +106,7 @@ class WolfSSLTestFactory { caJKS = in.concat(caJKS); rsaJKS = in.concat(rsaJKS); googleCACert = in.concat(googleCACert); - exampleCert = in.concat(exampleCert); + exampleComCert = in.concat(exampleComCert); } private boolean isIDEFile() { diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java index b00dd15..4d5792d 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLX509Test.java @@ -571,7 +571,7 @@ public class WolfSSLX509Test { List found = new ArrayList<>(); try { - x509 = new WolfSSLX509(tf.exampleCert); + x509 = new WolfSSLX509(tf.exampleComCert); Collection subjectAltNames = x509.getSubjectAlternativeNames(); if (subjectAltNames == null) {