From e945bf801d014bc169e5fd5385b7d6bbd438484b Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Wed, 21 Jun 2023 16:41:15 -0600 Subject: [PATCH 1/2] JNI: add X509v3 certificate generation support to WolfSSLCertificate class, supporting key usage, extended key usage, subject alt name, and basic constraints extensions. Self signed and CA-signed support, along with example app. Update example certs to match current wolfssl. --- .gitignore | 1 + IDE/WIN/wolfssljni.vcxproj | 2 + IDE/WIN/wolfssljni.vcxproj.filters | 6 + examples/README.md | 22 + examples/X509v3CertificateGeneration.java | 690 ++++++++++ examples/X509v3CertificateGeneration.sh | 51 + examples/certs/ca-cert.pem | 56 +- examples/certs/ca-ecc-cert.pem | 22 +- examples/certs/ca-key.der | Bin 0 -> 1192 bytes examples/certs/ca-keyPkcs8.der | Bin 0 -> 1218 bytes examples/certs/client-cert.der | Bin 1313 -> 1313 bytes examples/certs/client-cert.pem | 60 +- examples/certs/client-key.der | Bin 0 -> 1192 bytes examples/certs/client-keyPub.der | Bin 0 -> 294 bytes examples/certs/crl/cliCrl.pem | 54 +- examples/certs/crl/crl.pem | 52 +- examples/certs/crl/crl.revoked | 56 +- examples/certs/crl/eccCliCRL.pem | 22 +- examples/certs/crl/eccSrvCRL.pem | 22 +- examples/certs/server-cert.pem | 112 +- examples/certs/server-ecc.pem | 22 +- examples/certs/update-certs.sh | 31 +- examples/provider/all.jks | Bin 18450 -> 18452 bytes examples/provider/all_mixed.jks | Bin 17547 -> 17547 bytes examples/provider/ca-client.jks | Bin 3779 -> 3779 bytes examples/provider/ca-server.jks | Bin 3539 -> 3541 bytes examples/provider/cacerts.jks | Bin 11667 -> 11669 bytes examples/provider/client-ecc.jks | Bin 1141 -> 1141 bytes examples/provider/client-rsa-1024.jks | Bin 1830 -> 1830 bytes examples/provider/client-rsa.jks | Bin 2670 -> 2670 bytes examples/provider/client.jks | Bin 3775 -> 3775 bytes examples/provider/server-ecc.jks | Bin 952 -> 952 bytes examples/provider/server-rsa-1024.jks | Bin 2837 -> 2837 bytes examples/provider/server-rsa.jks | Bin 3912 -> 3912 bytes examples/provider/server.jks | Bin 4828 -> 4828 bytes java.sh | 3 +- native/com_wolfssl_WolfSSL.c | 6 + native/com_wolfssl_WolfSSL.h | 28 + native/com_wolfssl_WolfSSLCertificate.c | 770 +++++++++++ native/com_wolfssl_WolfSSLCertificate.h | 116 ++ native/com_wolfssl_WolfSSLX509Name.c | 126 ++ native/com_wolfssl_WolfSSLX509Name.h | 39 + src/java/com/wolfssl/WolfSSL.java | 23 + src/java/com/wolfssl/WolfSSLCertificate.java | 1152 ++++++++++++++--- src/java/com/wolfssl/WolfSSLX509Name.java | 527 ++++++++ .../jsse/WolfSSLInternalVerifyCb.java | 4 +- .../provider/jsse/WolfSSLTrustManager.java | 3 + .../wolfssl/provider/jsse/WolfSSLX509.java | 15 +- .../wolfssl/test/WolfSSLCertificateTest.java | 778 ++++++++++- src/test/com/wolfssl/test/WolfSSLTest.java | 13 + 50 files changed, 4388 insertions(+), 496 deletions(-) create mode 100644 examples/X509v3CertificateGeneration.java create mode 100755 examples/X509v3CertificateGeneration.sh create mode 100644 examples/certs/ca-key.der create mode 100644 examples/certs/ca-keyPkcs8.der create mode 100644 examples/certs/client-key.der create mode 100644 examples/certs/client-keyPub.der create mode 100644 native/com_wolfssl_WolfSSLX509Name.c create mode 100644 native/com_wolfssl_WolfSSLX509Name.h create mode 100644 src/java/com/wolfssl/WolfSSLX509Name.java diff --git a/.gitignore b/.gitignore index 0f7b6e25..9e43ca8a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ IDE/WIN/DLL Debug IDE/WIN/DLL Debug FIPS IDE/WIN/DLL Release IDE/WIN/DLL Release FIPS +examples/certs/generated # RPM package files rpm/spec diff --git a/IDE/WIN/wolfssljni.vcxproj b/IDE/WIN/wolfssljni.vcxproj index 8d91e019..68285ef5 100644 --- a/IDE/WIN/wolfssljni.vcxproj +++ b/IDE/WIN/wolfssljni.vcxproj @@ -43,6 +43,7 @@ + @@ -55,6 +56,7 @@ + diff --git a/IDE/WIN/wolfssljni.vcxproj.filters b/IDE/WIN/wolfssljni.vcxproj.filters index e911186e..c3300061 100644 --- a/IDE/WIN/wolfssljni.vcxproj.filters +++ b/IDE/WIN/wolfssljni.vcxproj.filters @@ -42,6 +42,9 @@ Source Files + + Source Files + @@ -77,5 +80,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index cf48f3c7..6ab988d8 100644 --- a/examples/README.md +++ b/examples/README.md @@ -41,6 +41,28 @@ argument: $ ./examples/server.sh --help ``` +## X509v3 Certificate Generation Example + +An example is included which will generate self-signed and CA-signed +X.509v3 certificates using the wolfSSL JNI library `WolfSSLCertificate` +class. + +**X509v3CertificateGeneration.java** - Certificate generation example + +This example is compiled when the `ant examples` target is executed, and can +be run afterwards with the provided bash script: + +``` +$ cd +$ ./examples/X509v3CertificateGeneration.sh +``` + +This will write out generated certificates to the following directory: + +``` +examples/certs/generated/ +``` + ## Support Please contact the wolfSSL support team at support@wolfssl.com with any diff --git a/examples/X509v3CertificateGeneration.java b/examples/X509v3CertificateGeneration.java new file mode 100644 index 00000000..d365c66a --- /dev/null +++ b/examples/X509v3CertificateGeneration.java @@ -0,0 +1,690 @@ +/* X509v3CertificateGeneration.java + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.Instant; +import java.time.Duration; +import java.util.Date; +import java.math.BigInteger; + +import java.io.FileInputStream; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.KeyPair; +import java.security.PublicKey; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.interfaces.RSAPrivateKey; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.cert.CertificateException; + +import com.wolfssl.WolfSSL; +import com.wolfssl.WolfSSLCertificate; +import com.wolfssl.WolfSSLX509Name; +import com.wolfssl.WolfSSLException; +import com.wolfssl.WolfSSLJNIException; + +/** + * Example application that demonstrates X509v3 certifiate generation + * including various combinations: + * + * Self-signed certificate using files as input for certs/keys + * Self-signed certificate using arrays as input for certs/keys + * Self-signed certificate using generated certs and keys + * + * CA-signed certificate using files as input for certs/keys + * CA-signed certificate using arrays as input for certs/keys + * CA-signed certificate using generated certs and keys + * + * Each sub-example is contained in a separate method. + * + * When run, generated certificates are written out to PEM and DER files, + * with location specified by variables at the top of this class. + */ +public class X509v3CertificateGeneration { + + private static String CERT_DIR = "../certs/"; + private static String GEN_DIR = CERT_DIR + "generated/"; + private static String CERT_DIR_FROM_ROOT = "./exammples/certs/generated/"; + + /* Existing certs/keys used for cert gen example with files */ + private static String caCertPem = CERT_DIR + "ca-cert.pem"; + private static String caKeyDer = CERT_DIR + "ca-key.der"; + private static String caKeyPkcs8Der = CERT_DIR + "ca-keyPkcs8.der"; + private static String clientKeyDer = CERT_DIR + "client-key.der"; + private static String clientKeyPubDer = CERT_DIR + "client-keyPub.der"; + + /* Generated self-signed certificate locations. + * Generated self-signed certs have isCA Basic Constraint set true + * in these examples. */ + private static String selfSignedUsingFilesDer = + GEN_DIR + "self-signed-using-files.der"; + private static String selfSignedUsingFilesPem = + GEN_DIR + "self-signed-using-files.pem"; + private static String selfSignedUsingArraysDer = + GEN_DIR + "self-signed-using-arrays.der"; + private static String selfSignedUsingArraysPem = + GEN_DIR + "self-signed-using-arrays.pem"; + private static String selfSignedUsingGeneratedKeysDer = + GEN_DIR + "self-signed-generated-keys.der"; + private static String selfSignedUsingGeneratedKeysPem = + GEN_DIR + "self-signed-generated-keys.pem"; + + /* Generated CA-signed certificate locations. + * Generated CA-signed certs have isCA Basic Constraint set false + * in these examples. */ + private static String caSignedUsingFilesDer = + GEN_DIR + "ca-signed-using-files.der"; + private static String caSignedUsingFilesPem = + GEN_DIR + "ca-signed-using-files.pem"; + private static String caSignedUsingArraysDer = + GEN_DIR + "ca-signed-using-arrays.der"; + private static String caSignedUsingArraysPem = + GEN_DIR + "ca-signed-using-arrays.pem"; + private static String caSignedUsingGeneratedKeysDer = + GEN_DIR + "ca-signed-generated-keys.der"; + private static String caSignedUsingGeneratedKeysPem = + GEN_DIR + "ca-signed-generated-keys.pem"; + + /* Example Extension values */ + private static String test_KEY_USAGE = + "digitalSignature,keyEncipherment,dataEncipherment"; + private static String test_EXT_KEY_USAGE = + "clientAuth,serverAuth"; + private static String test_ALT_NAME = + "alt.example.com"; + + private void writeFile(String path, byte[] bytes) + throws IOException { + + File genDir = new File(GEN_DIR); + if (!genDir.exists()) { + genDir.mkdir(); + } + Files.write(new File(path).toPath(), bytes); + } + + private WolfSSLX509Name generateTestSubjectName() + throws WolfSSLException { + + WolfSSLX509Name subjectName = new WolfSSLX509Name(); + subjectName.setCountryName("US"); + subjectName.setStateOrProvinceName("Montana"); + subjectName.setStreetAddress("12345 Test Address"); + subjectName.setLocalityName("Bozeman"); + subjectName.setSurname("Test Surname"); + subjectName.setCommonName("example.com"); + subjectName.setEmailAddress("support@example.com"); + subjectName.setOrganizationName("wolfSSL Inc."); + subjectName.setOrganizationalUnitName("Test and Development"); + subjectName.setPostalCode("59715"); + subjectName.setUserId("TestUserID"); + + return subjectName; + } + + /** + * Generate example certificate using the following files as input + * to the certificate generation process: + * + * clientKeyPubDer - Existing client public key in DER format + * clientKeyDer - Existing client private key in DER format + * + * Generates and writes certificate out to the following paths in + * both PEM and DER format (see variable values above): + * selfSignedUsingFilesDer (DER format) + * selfSignedUsingFilesPem (PEM format) + * + * @throws WolfSSLException if error occurs during certificate generation + * process. + * @throws WolfSSLJNIException if native JNI error occurs + * @throws IOException on error writing to output file locations + */ + public void generateSelfSignedUsingFiles() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException { + + System.out.print("\nGenerating self-signed cert using files"); + + /* Create new certificate object */ + WolfSSLCertificate x509 = new WolfSSLCertificate(); + + /* Set notBefore/notAfter validity dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = generateTestSubjectName(); + x509.setSubjectName(subjectName); + + /* Not setting Issuer, since generating self-signed cert */ + + /* Set Public Key from existing public key DER file */ + x509.setPublicKey(clientKeyPubDer, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1); + + /* Add Extensions */ + x509.addExtension(WolfSSL.NID_key_usage, test_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_ext_key_usage, test_EXT_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_subject_alt_name, test_ALT_NAME, false); + x509.addExtension(WolfSSL.NID_basic_constraints, true, true); + + /* Sign certificate, self-signed using existing client key DER */ + x509.signCert(clientKeyDer, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1, "SHA256"); + + /* Output to DER and PEM files */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + /* Write out generated certs to files */ + writeFile(selfSignedUsingFilesDer, derCert); + writeFile(selfSignedUsingFilesPem, pemCert); + + /* Test converting to X509Certificate */ + X509Certificate tmpX509 = x509.getX509Certificate(); + + System.out.println("... "); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(selfSignedUsingFilesDer).getFileName()); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(selfSignedUsingFilesPem).getFileName()); + + /* Free native memory */ + subjectName.free(); + x509.free(); + } + + /** + * Generate example certificate using the following files in array format + * as input to the certificate generation process: + * + * clientKeyPubDer - Existing client public key in DER format + * clientKeyDer - Existing client private key in DER format + * + * Generates and writes certificate out to the following paths in + * both PEM and DER format (see variable values above): + * selfSignedUsingArraysDer (DER format) + * selfSignedUsingArraysPem (PEM format) + * + * @throws WolfSSLException if error occurs during certificate generation + * process. + * @throws WolfSSLJNIException if native JNI error occurs + * @throws IOException on error writing to output file locations + */ + public void generateSelfSignedUsingArrays() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException { + + System.out.print("\nGenerating self-signed cert using arrays"); + + /* Create new certificate object */ + WolfSSLCertificate x509 = new WolfSSLCertificate(); + + /* Set notBefore/notAfter validity dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = generateTestSubjectName(); + x509.setSubjectName(subjectName); + + /* Not setting Issuer, since generating self-signed cert */ + + /* Set Public Key from existing public key DER file */ + byte[] pubKey = Files.readAllBytes(Paths.get(clientKeyPubDer)); + x509.setPublicKey(pubKey, WolfSSL.RSAk, WolfSSL.SSL_FILETYPE_ASN1); + + /* Add Extensions */ + x509.addExtension(WolfSSL.NID_key_usage, test_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_ext_key_usage, test_EXT_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_subject_alt_name, test_ALT_NAME, false); + x509.addExtension(WolfSSL.NID_basic_constraints, true, true); + + /* Sign certificate, self-signed using existing client key DER */ + byte[] privKey = Files.readAllBytes(Paths.get(clientKeyDer)); + x509.signCert(privKey, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1, "SHA256"); + + /* Output to DER and PEM files */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + /* Write out generated certs to files */ + writeFile(selfSignedUsingArraysDer, derCert); + writeFile(selfSignedUsingArraysPem, pemCert); + + /* Test converting to X509Certificate */ + X509Certificate tmpX509 = x509.getX509Certificate(); + + System.out.println("... "); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(selfSignedUsingArraysDer).getFileName()); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(selfSignedUsingArraysPem).getFileName()); + + /* Free native memory */ + subjectName.free(); + x509.free(); + } + + /** + * Generate example certificate using generated keys for the certificate + * public and private key, to be used in the certificate generation + * process. + * + * Generates and writes certificate out to the following paths in + * both PEM and DER format (see variable values above): + * selfSignedUsingGeneratedKeysDer (DER format) + * selfSignedUsingGeneratedKeysPem (PEM format) + * + * @throws WolfSSLException if error occurs during certificate generation + * process. + * @throws WolfSSLJNIException if native JNI error occurs + * @throws IOException on error writing to output file locations + */ + public void generateSelfSignedUsingGeneratedKeys() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException, NoSuchAlgorithmException { + + System.out.print("\nGenerating self-signed cert with generated keys"); + + /* Create new certificate object */ + WolfSSLCertificate x509 = new WolfSSLCertificate(); + + /* Set notBefore/notAfter validity dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = generateTestSubjectName(); + x509.setSubjectName(subjectName); + + /* Not setting Issuer, since generating self-signed cert */ + + /* Set Public Key from generated java.security.PublicKey */ + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(2048); + KeyPair keyPair = kpg.generateKeyPair(); + PublicKey pubKey = keyPair.getPublic(); + x509.setPublicKey(pubKey); + + /* Add Extensions */ + x509.addExtension(WolfSSL.NID_key_usage, test_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_ext_key_usage, test_EXT_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_subject_alt_name, test_ALT_NAME, false); + x509.addExtension(WolfSSL.NID_basic_constraints, true, true); + + /* Sign certificate, self-signed with java.security.PrivateKey */ + PrivateKey privKey = keyPair.getPrivate(); + x509.signCert(privKey, "SHA256"); + + /* Output to DER and PEM files */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + /* Write out generated certs to files */ + writeFile(selfSignedUsingGeneratedKeysDer, derCert); + writeFile(selfSignedUsingGeneratedKeysPem, pemCert); + + /* Test converting to X509Certificate */ + X509Certificate tmpX509 = x509.getX509Certificate(); + + System.out.println("... "); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(selfSignedUsingGeneratedKeysDer).getFileName()); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(selfSignedUsingGeneratedKeysPem).getFileName()); + + /* Free native memory */ + subjectName.free(); + x509.free(); + } + + /** + * ----------------------------------------------------------------------- + * Below are examples of CA-signed certificate generation + * ----------------------------------------------------------------------- + */ + + /** + * Generate example CA-signed certificate using the following files as + * input to the certificate generation process: + * + * caCertPem - Existing CA certificate in PEM format + * clientKeyPubDer - Existing client public key in DER format + * clientKeyDer - Existing client private key in DER format + * + * Generates and writes certificate out to the following paths in + * both PEM and DER format (see variable values above): + * caSignedUsingFilesDer (DER format) + * caSignedUsingFilesPem (PEM format) + * + * @throws WolfSSLException if error occurs during certificate generation + * process. + * @throws WolfSSLJNIException if native JNI error occurs + * @throws IOException on error writing to output file locations + */ + public void generateCASignedUsingFiles() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException { + + System.out.print("\nGenerating CA-signed cert using files"); + + /* Create new certificate object */ + WolfSSLCertificate x509 = new WolfSSLCertificate(); + + /* Set notBefore/notAfter validity dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = generateTestSubjectName(); + x509.setSubjectName(subjectName); + + /* Set Issuer Name from existing cert file wrapped in + * WolfSSLCertificate object */ + WolfSSLCertificate issuer = new WolfSSLCertificate(caCertPem, + WolfSSL.SSL_FILETYPE_PEM); + x509.setIssuerName(issuer); + + /* Set Public Key from existing public key DER file */ + x509.setPublicKey(clientKeyPubDer, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1); + + /* Add Extensions */ + x509.addExtension(WolfSSL.NID_key_usage, test_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_ext_key_usage, test_EXT_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_subject_alt_name, test_ALT_NAME, false); + x509.addExtension(WolfSSL.NID_basic_constraints, true, true); + + /* Sign certificate, CA-signed using existing CA key DER */ + x509.signCert(caKeyDer, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1, "SHA256"); + + /* Output to DER and PEM files */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + /* Write out generated certs to files */ + writeFile(caSignedUsingFilesDer, derCert); + writeFile(caSignedUsingFilesPem, pemCert); + + /* Test converting to X509Certificate */ + X509Certificate tmpX509 = x509.getX509Certificate(); + + System.out.println("... "); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(caSignedUsingFilesDer).getFileName()); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(caSignedUsingFilesPem).getFileName()); + + /* Free native memory */ + subjectName.free(); + x509.free(); + } + + /** + * Generate example CA-signed certificate using the following files in + * array format as input to the certificate generation process: + * + * caCertPem - Existing CA certificate in PEM format + * clientKeyPubDer - Existing client public key in DER format + * clientKeyDer - Existing client private key in DER format + * + * Generates and writes certificate out to the following paths in + * both PEM and DER format (see variable values above): + * caSignedUsingArraysDer (DER format) + * caSignedUsingArraysPem (PEM format) + * + * @throws WolfSSLException if error occurs during certificate generation + * process. + * @throws WolfSSLJNIException if native JNI error occurs + * @throws IOException on error writing to output file locations + */ + public void generateCASignedUsingArrays() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException { + + System.out.print("\nGenerating CA-signed cert using arrays"); + + /* Create new certificate object */ + WolfSSLCertificate x509 = new WolfSSLCertificate(); + + /* Set notBefore/notAfter validity dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = generateTestSubjectName(); + x509.setSubjectName(subjectName); + + /* Set Issuer Name from existing cert file ready into a byte array and + * wrapped in WolfSSLCertificate object */ + WolfSSLCertificate issuer = new WolfSSLCertificate( + Files.readAllBytes(Paths.get(caCertPem)), + WolfSSL.SSL_FILETYPE_PEM); + x509.setIssuerName(issuer); + + /* Set Public Key from existing public key DER file */ + byte[] pubKey = Files.readAllBytes(Paths.get(clientKeyPubDer)); + x509.setPublicKey(pubKey, WolfSSL.RSAk, WolfSSL.SSL_FILETYPE_ASN1); + + /* Add Extensions */ + x509.addExtension(WolfSSL.NID_key_usage, test_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_ext_key_usage, test_EXT_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_subject_alt_name, test_ALT_NAME, false); + x509.addExtension(WolfSSL.NID_basic_constraints, true, true); + + /* Sign certificate, self-signed using existing client key DER */ + byte[] privKey = Files.readAllBytes(Paths.get(caKeyDer)); + x509.signCert(privKey, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1, "SHA256"); + + /* Output to DER and PEM files */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + /* Write out generated certs to files */ + writeFile(caSignedUsingArraysDer, derCert); + writeFile(caSignedUsingArraysPem, pemCert); + + /* Test converting to X509Certificate */ + X509Certificate tmpX509 = x509.getX509Certificate(); + + System.out.println("... "); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(caSignedUsingArraysDer).getFileName()); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(caSignedUsingArraysPem).getFileName()); + + /* Free native memory */ + subjectName.free(); + x509.free(); + } + + /** + * Generate example CA-signed certificate using generated keys for the + * certificate public and private key, to be used in the certificate + * generation process. + * + * Generates and writes certificate out to the following paths in + * both PEM and DER format (see variable values above): + * caSignedUsingGeneratedKeysDer (DER format) + * caSignedUsingGeneratedKeysPem (PEM format) + * + * @throws WolfSSLException if error occurs during certificate generation + * process. + * @throws WolfSSLJNIException if native JNI error occurs + * @throws IOException on error writing to output file locations + */ + public void generateCASignedUsingGeneratedKeys() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException, NoSuchAlgorithmException, + InvalidKeySpecException { + + System.out.print("\nGenerating CA-signed cert with generated keys"); + + /* Create new certificate object */ + WolfSSLCertificate x509 = new WolfSSLCertificate(); + + /* Set notBefore/notAfter validity dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = generateTestSubjectName(); + x509.setSubjectName(subjectName); + + /* Set Issuer Name from existing cert file wrapped in + * WolfSSLCertificate object */ + WolfSSLCertificate issuer = new WolfSSLCertificate(caCertPem, + WolfSSL.SSL_FILETYPE_PEM); + X509Certificate issuerX509 = issuer.getX509Certificate(); + x509.setIssuerName(issuerX509); + + /* Set Public Key from generated java.security.PublicKey */ + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(2048); + KeyPair keyPair = kpg.generateKeyPair(); + PublicKey pubKey = keyPair.getPublic(); + x509.setPublicKey(pubKey); + + /* Add Extensions */ + x509.addExtension(WolfSSL.NID_key_usage, test_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_ext_key_usage, test_EXT_KEY_USAGE, false); + x509.addExtension(WolfSSL.NID_subject_alt_name, test_ALT_NAME, false); + x509.addExtension(WolfSSL.NID_basic_constraints, true, true); + + /* Sign certificate, using CA's private key */ + byte[] privBytes = Files.readAllBytes(Paths.get(caKeyPkcs8Der)); + KeyFactory kf = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privBytes); + RSAPrivateKey rsaPriv = (RSAPrivateKey)kf.generatePrivate(spec); + x509.signCert((PrivateKey)rsaPriv, "SHA256"); + + /* Output to DER and PEM files */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + /* Write out generated certs to files */ + writeFile(caSignedUsingGeneratedKeysDer, derCert); + writeFile(caSignedUsingGeneratedKeysPem, pemCert); + + /* Test converting to X509Certificate */ + X509Certificate tmpX509 = x509.getX509Certificate(); + + System.out.println("... "); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(caSignedUsingGeneratedKeysDer).getFileName()); + System.out.println(" " + CERT_DIR_FROM_ROOT + + Paths.get(caSignedUsingGeneratedKeysPem).getFileName()); + + /* Free native memory */ + subjectName.free(); + x509.free(); + } + + public void run(String[] args) { + + int ret = 0; + + try { + /* Initialize and load native wolfSSL library, enable debugging */ + WolfSSL.loadLibrary(); + WolfSSL sslLib = new WolfSSL(); + + /* Enable debugging if desired */ + //sslLib.debuggingON(); + + System.out.println( + "wolfSSL JNI X509v3 Certificate Generation Example"); + + /* Generate self-signed example certificates */ + generateSelfSignedUsingFiles(); + generateSelfSignedUsingArrays(); + generateSelfSignedUsingGeneratedKeys(); + + /* Generate CA-signed example certificates */ + generateCASignedUsingFiles(); + generateCASignedUsingArrays(); + generateCASignedUsingGeneratedKeys(); + + } catch (WolfSSLException | WolfSSLJNIException | + IOException | CertificateException | + NoSuchAlgorithmException | InvalidKeySpecException e) { + e.printStackTrace(); + + /* exit with error */ + System.exit(1); + } + + } /* end run() */ + + public static void main(String[] args) { + new X509v3CertificateGeneration().run(args); + } + +} /* end X509v3CertificateGeneration */ + diff --git a/examples/X509v3CertificateGeneration.sh b/examples/X509v3CertificateGeneration.sh new file mode 100755 index 00000000..dfeb0afc --- /dev/null +++ b/examples/X509v3CertificateGeneration.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Allow user to override which openssl binary is used to verify certs +if [ -z "${OPENSSL}" ]; then + OPENSSL=openssl +fi + +cd ./examples/build +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../lib/:/usr/local/lib +java -classpath ../../lib/wolfssl.jar:./ -Dsun.boot.library.path=../../lib/ -Xcheck:jni X509v3CertificateGeneration $@ + +if [ $? != 0 ]; then + printf "\nExample failed\n" + exit -1 +else + printf "\nExample passed\n" +fi + +which $OPENSSL > /dev/null +if [ $? != 0 ]; then + printf "openssl not detected, skipping cert verification\n" + exit -1 +fi + +printf "\nVerifying certs with openssl...\n" + +printf "Testing each can be opened with openssl x509 -text\n" + +# Test reading each DER cert +CERT_FILES="../certs/generated/*.der" +for f in $CERT_FILES +do + $OPENSSL x509 -inform DER -in $f -text -noout > /dev/null + if [ $? != 0 ]; then + printf "File not readable with openssl x509: $f\n" + exit -1 + fi +done + +# Test reading each PEM cert +CERT_FILES="../certs/generated/*.pem" +for f in $CERT_FILES +do + $OPENSSL x509 -inform PEM -in $f -text -noout > /dev/null + if [ $? != 0 ]; then + printf "File not readable with openssl x509: $f\n" + exit -1 + fi +done + +printf "Verification successful\n" diff --git a/examples/certs/ca-cert.pem b/examples/certs/ca-cert.pem index 2c7fc177..58688a0e 100644 --- a/examples/certs/ca-cert.pem +++ b/examples/certs/ca-cert.pem @@ -2,12 +2,12 @@ Certificate: Data: Version: 3 (0x2) Serial Number: - 26:8c:93:f9:f9:f4:1e:b3:01:72:94:55:67:6d:e2:f8:3d:da:e9:f4 + 2c:80:ce:db:47:9d:07:66:92:3d:68:d7:ca:ac:90:4f:ca:69:41:4b Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com Validity - Not Before: Feb 15 12:50:24 2022 GMT - Not After : Nov 11 12:50:24 2024 GMT + Not Before: Dec 16 21:17:49 2022 GMT + Not After : Sep 11 21:17:49 2025 GMT Subject: C = US, ST = Montana, L = Bozeman, O = Sawtooth, OU = Consulting, CN = www.wolfssl.com, emailAddress = info@wolfssl.com Subject Public Key Info: Public Key Algorithm: rsaEncryption @@ -38,7 +38,7 @@ Certificate: X509v3 Authority Key Identifier: keyid:27:8E:67:11:74:C3:26:1D:3F:ED:33:63:B3:A4:D8:1D:30:E5:E8:D5 DirName:/C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=info@wolfssl.com - serial:26:8C:93:F9:F9:F4:1E:B3:01:72:94:55:67:6D:E2:F8:3D:DA:E9:F4 + serial:2C:80:CE:DB:47:9D:07:66:92:3D:68:D7:CA:AC:90:4F:CA:69:41:4B X509v3 Basic Constraints: CA:TRUE @@ -47,27 +47,27 @@ Certificate: X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication Signature Algorithm: sha256WithRSAEncryption - 62:e4:1b:28:3c:9d:d2:60:a9:55:be:6a:f6:20:f2:da:e8:a1: - 1a:97:b1:90:77:82:ed:c7:77:29:53:33:18:10:62:e0:bd:93: - 1b:d2:d6:a1:80:43:1d:64:f1:42:92:ec:b7:b8:f0:6b:da:59: - 83:f4:b8:87:e6:fc:70:21:ea:62:32:70:68:14:0e:dc:b4:f1: - 66:e2:6e:ab:d2:72:6f:da:df:71:f6:3d:27:97:7d:be:e1:d1: - ac:16:ad:d7:4f:aa:9d:0c:1e:6e:a9:5e:7d:57:5b:3c:c7:6d: - d2:f2:5c:c3:dc:3d:36:99:8e:ab:c0:7f:13:a5:f4:67:8b:e2: - a6:51:31:f1:03:91:00:a8:c4:c5:1d:7f:35:62:b8:1d:a0:a5: - ab:ec:32:68:ee:f3:ca:48:16:9f:f4:1e:7e:ea:fa:b0:86:15: - 52:36:6c:4b:58:44:a7:eb:20:78:6e:7e:e8:00:40:ac:98:d8: - 53:f3:13:4b:b8:98:66:50:63:ed:af:e5:a4:f6:c9:90:1c:84: - 0a:09:45:2f:a1:e1:37:63:b5:43:8c:a0:2e:7f:c4:d4:e1:ae: - b7:b9:45:13:f8:70:d5:79:06:4f:82:83:4b:98:d7:56:47:64: - 9a:6a:6d:8e:7a:9d:ef:83:0f:6b:75:0e:47:22:92:f3:b4:b2: - 84:61:1f:1c + ae:b0:a4:35:8e:8a:1b:a6:eb:b3:a2:57:cf:3a:1f:dc:6e:bc: + d2:d0:a6:4a:8f:88:0a:6e:74:d5:d1:7c:d1:44:b1:d4:3b:17: + 03:09:5a:46:ed:08:08:cf:f1:fd:20:07:67:c0:97:ec:35:f3: + 75:ca:20:61:98:3e:f5:4d:be:e6:9d:75:1e:e4:03:ad:8c:a6: + 1e:3d:ec:e4:1a:92:5b:f9:a3:ad:83:ca:4f:cd:aa:38:bb:6e: + ae:ad:fa:a7:46:f1:8b:73:ec:09:23:bc:f2:18:e5:b7:92:86: + 3e:a4:75:60:c7:3d:0f:3f:83:00:c3:06:08:9c:d1:54:d6:ba: + 6d:95:3d:34:a1:be:24:91:cc:20:03:11:5b:72:1c:d4:65:d0: + 11:88:75:26:04:26:ef:66:70:e6:3b:38:87:9c:53:71:1b:09: + 51:70:50:99:4c:31:0c:62:44:57:30:60:04:fc:12:2c:a3:24: + b4:f7:11:d5:0e:b5:21:0b:ed:86:11:67:4d:36:fa:57:a0:59: + 55:21:b3:6d:e4:77:5e:ec:7e:f0:09:13:8e:99:98:b2:e1:82: + b6:4b:3e:0f:41:a6:0c:cd:49:99:7e:e4:8a:cb:37:ed:53:cf: + 86:5d:a9:26:a8:e5:01:25:5a:b4:bc:25:35:f1:fa:5a:5c:ce: + d4:b8:9a:2c -----BEGIN CERTIFICATE----- -MIIE/zCCA+egAwIBAgIUJoyT+fn0HrMBcpRVZ23i+D3a6fQwDQYJKoZIhvcNAQEL +MIIE/zCCA+egAwIBAgIULIDO20edB2aSPWjXyqyQT8ppQUswDQYJKoZIhvcNAQEL BQAwgZQxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdC b3plbWFuMREwDwYDVQQKDAhTYXd0b290aDETMBEGA1UECwwKQ29uc3VsdGluZzEY MBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdv -bGZzc2wuY29tMB4XDTIyMDIxNTEyNTAyNFoXDTI0MTExMTEyNTAyNFowgZQxCzAJ +bGZzc2wuY29tMB4XDTIyMTIxNjIxMTc0OVoXDTI1MDkxMTIxMTc0OVowgZQxCzAJ BgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdCb3plbWFuMREw DwYDVQQKDAhTYXd0b290aDETMBEGA1UECwwKQ29uc3VsdGluZzEYMBYGA1UEAwwP d3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wuY29t @@ -82,12 +82,12 @@ BgNVHSMEgcwwgcmAFCeOZxF0wyYdP+0zY7Ok2B0w5ejVoYGapIGXMIGUMQswCQYD VQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjERMA8G A1UECgwIU2F3dG9vdGgxEzARBgNVBAsMCkNvbnN1bHRpbmcxGDAWBgNVBAMMD3d3 dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbYIU -JoyT+fn0HrMBcpRVZ23i+D3a6fQwDAYDVR0TBAUwAwEB/zAcBgNVHREEFTATggtl +LIDO20edB2aSPWjXyqyQT8ppQUswDAYDVR0TBAUwAwEB/zAcBgNVHREEFTATggtl eGFtcGxlLmNvbYcEfwAAATAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw -DQYJKoZIhvcNAQELBQADggEBAGLkGyg8ndJgqVW+avYg8trooRqXsZB3gu3HdylT -MxgQYuC9kxvS1qGAQx1k8UKS7Le48GvaWYP0uIfm/HAh6mIycGgUDty08WbibqvS -cm/a33H2PSeXfb7h0awWrddPqp0MHm6pXn1XWzzHbdLyXMPcPTaZjqvAfxOl9GeL -4qZRMfEDkQCoxMUdfzViuB2gpavsMmju88pIFp/0Hn7q+rCGFVI2bEtYRKfrIHhu -fugAQKyY2FPzE0u4mGZQY+2v5aT2yZAchAoJRS+h4TdjtUOMoC5/xNThrre5RRP4 -cNV5Bk+Cg0uY11ZHZJpqbY56ne+DD2t1DkcikvO0soRhHxw= +DQYJKoZIhvcNAQELBQADggEBAK6wpDWOihum67OiV886H9xuvNLQpkqPiApudNXR +fNFEsdQ7FwMJWkbtCAjP8f0gB2fAl+w183XKIGGYPvVNvuaddR7kA62Mph497OQa +klv5o62Dyk/Nqji7bq6t+qdG8Ytz7AkjvPIY5beShj6kdWDHPQ8/gwDDBgic0VTW +um2VPTShviSRzCADEVtyHNRl0BGIdSYEJu9mcOY7OIecU3EbCVFwUJlMMQxiRFcw +YAT8EiyjJLT3EdUOtSEL7YYRZ002+legWVUhs23kd17sfvAJE46ZmLLhgrZLPg9B +pgzNSZl+5IrLN+1Tz4ZdqSao5QElWrS8JTXx+lpcztS4miw= -----END CERTIFICATE----- diff --git a/examples/certs/ca-ecc-cert.pem b/examples/certs/ca-ecc-cert.pem index 1d0148d0..e4e4c7c5 100644 --- a/examples/certs/ca-ecc-cert.pem +++ b/examples/certs/ca-ecc-cert.pem @@ -2,12 +2,12 @@ Certificate: Data: Version: 3 (0x2) Serial Number: - 29:bf:2b:cd:bf:55:54:49:85:b3:69:4e:e1:85:37:79:1e:81:f9:c2 + 65:67:42:4c:06:e7:e4:c3:68:01:a9:94:a9:07:e6:fe:bd:2c:d6:3d Signature Algorithm: ecdsa-with-SHA256 Issuer: C = US, ST = Washington, L = Seattle, O = wolfSSL, OU = Development, CN = www.wolfssl.com, emailAddress = info@wolfssl.com Validity - Not Before: Feb 15 12:50:24 2022 GMT - Not After : Nov 11 12:50:24 2024 GMT + Not Before: Dec 16 21:17:49 2022 GMT + Not After : Sep 11 21:17:49 2025 GMT Subject: C = US, ST = Washington, L = Seattle, O = wolfSSL, OU = Development, CN = www.wolfssl.com, emailAddress = info@wolfssl.com Subject Public Key Info: Public Key Algorithm: id-ecPublicKey @@ -31,16 +31,16 @@ Certificate: X509v3 Key Usage: critical Digital Signature, Certificate Sign, CRL Sign Signature Algorithm: ecdsa-with-SHA256 - 30:44:02:20:78:ed:4c:1c:a7:2d:b3:35:0b:1d:46:a3:37:31: - 0b:8a:05:39:c8:28:31:58:35:f1:98:f7:4b:72:c0:4f:e6:7f: - 02:20:02:f2:09:2b:3a:e1:36:92:bf:58:6a:03:12:2d:79:e6: - bd:06:45:61:b9:0e:39:e1:9c:f0:a8:2e:0b:1e:8c:b2 + 30:46:02:21:00:b0:12:16:03:26:79:d4:6b:94:d9:7e:ca:e1: + 2d:24:64:ef:11:6e:f2:12:81:e4:ce:1d:77:7d:ca:5c:47:50: + 62:02:21:00:80:bf:46:3c:5d:d8:e5:ab:47:ce:a2:19:bd:21: + de:85:6f:ab:c9:8f:01:f3:ab:1b:b9:e1:53:d6:24:77:a6:4d -----BEGIN CERTIFICATE----- -MIIClDCCAjugAwIBAgIUKb8rzb9VVEmFs2lO4YU3eR6B+cIwCgYIKoZIzj0EAwIw +MIICljCCAjugAwIBAgIUZWdCTAbn5MNoAamUqQfm/r0s1j0wCgYIKoZIzj0EAwIw gZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdT ZWF0dGxlMRAwDgYDVQQKDAd3b2xmU1NMMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEY MBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdv -bGZzc2wuY29tMB4XDTIyMDIxNTEyNTAyNFoXDTI0MTExMTEyNTAyNFowgZcxCzAJ +bGZzc2wuY29tMB4XDTIyMTIxNjIxMTc0OVoXDTI1MDkxMTIxMTc0OVowgZcxCzAJ BgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxl MRAwDgYDVQQKDAd3b2xmU1NMMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEYMBYGA1UE AwwPd3d3LndvbGZzc2wuY29tMR8wHQYJKoZIhvcNAQkBFhBpbmZvQHdvbGZzc2wu @@ -48,6 +48,6 @@ Y29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAtPZbtYBjkXIuZAx5cBM456t KTiYuhDW6QkqgKkuFyq5ir8zg0bjlQvkd0C1O0NFMw9hU3w3RMHL/IDK6EPqp6Nj MGEwHQYDVR0OBBYEFFaOmsPwQt4YuUVVbvmTz+rD86UhMB8GA1UdIwQYMBaAFFaO msPwQt4YuUVVbvmTz+rD86UhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgGGMAoGCCqGSM49BAMCA0cAMEQCIHjtTBynLbM1Cx1GozcxC4oFOcgoMVg18Zj3 -S3LAT+Z/AiAC8gkrOuE2kr9YagMSLXnmvQZFYbkOOeGc8KguCx6Msg== +AgGGMAoGCCqGSM49BAMCA0kAMEYCIQCwEhYDJnnUa5TZfsrhLSRk7xFu8hKB5M4d +d33KXEdQYgIhAIC/Rjxd2OWrR86iGb0h3oVvq8mPAfOrG7nhU9Ykd6ZN -----END CERTIFICATE----- diff --git a/examples/certs/ca-key.der b/examples/certs/ca-key.der new file mode 100644 index 0000000000000000000000000000000000000000..14456f3e453ba04c32952d0db72fecdeb153eb3e GIT binary patch literal 1192 zcmV;Z1Xueof&`=j0RRGm0RaHN49YDOvL1v&Tg^BhO7cy05b?G(pWn)T1DMmS-UDXt zD)HE`eQpO-3lNwgO@PZ1Am_|a-bH=Ma(6Q7%8Xw{Njp7uPtM2>z2;Z~ns*NeC7Tr%h)7QZZ*EPMGac zMIE^W*$eF0D6>nw?KXJ=0|5X50)hbmJ#J258iaqHg?!;l2YlexnJV6$`8G5TcMd)X z>QChcCe-#g_umZ<94-c;^eSkaV{+p)<^++EwZXBZRIJy=`$3@Ab#J{3PQS5I=wC@D zm{v!}-s$Q*U;)1<+%dmNUz16PdVyP(OHImLI8V3XveU;Q+B_162jm;vL+t46RAJ}# z?WPMZ_1}Vj#vfrBoTP&}-ywyGZ+EYT6*35-S_>v&`)~}(oH%{FBJS&>s1^YEihv#f zgs4hE_=E#zFC$won`%rvXL$JO;FFoh2=BRNw4JjL0)c@5;dVuUS+>(j-wN*%)(`Nv%PKd&r}(u^^)WTA zw5tsL;n*Cwp*?YEX}_weM=&jFZE z+;mi`ZC+YIG5-IWwx9*wsSs57YtX8L0)c=b(*%k{>rl6RX1|9k<|t0;gW~Bm;qnnj z|DpB#pDpD&f&2jjZ&R&QC$>`VR%;d67!vbzew(y z4#ABO|7Dt;EgFiHTFAhqrG#Og)Fip@sh!Dp3&(I~J-WzL-_kST^?&&%VZK*I-M2*- zB=sZYI1Z5~?&BcX6v&iEcR+VV7@iHzc|TV%RtZUGzLZ!`_Qb2=iR0snzy(z-B*03S G1Sgsk)I)m! literal 0 HcmV?d00001 diff --git a/examples/certs/ca-keyPkcs8.der b/examples/certs/ca-keyPkcs8.der new file mode 100644 index 0000000000000000000000000000000000000000..58ac8d458c9cf304931ee8adcecbb063732422bb GIT binary patch literal 1218 zcmV;z1U>sOf&{(-0RS)!1_>&LNQUrs4#*Aqyhl|0)hbn0KW{%EflgI zghE@*I3G&#O?43Qwl$yM%6$Wv)2!YDX6`ES*sy(W2UH6Xm?2Go%Mu{x%un7$eaUin zGV02ZyJ=Do123ramBsOkVpbdPXK$nsL6xlvo8zUxu+ngLP%vAl=m;!)?Wdx8jW{VB ztjF#0e3h`3f_+I`IL&t@@4bL^Q)6g009Dm0RTO2 zPGA~@f1QPV;Y$a6;MSQc-kte2G!AzTJ_zbhO5cpzbM=>ze!({Nr!rYTb4^r z%3L^4x8btW$06E05{C!m8{9+e=uZ9&e z2%=gGCSm(<49c81eY_&>>!YX^0Qri59sq=>N5nITPxrK|2@xyRtUM~A^_&vWxIzRo!WoaF+6fdJul zMSxkh(@Eb7?-JGz@VCnOGER)&5EVj;nX)<=0hw_T*hI@hsuAofs~K?GCnKPJ|1k@{#R>?+)v@#oz8 zbMSdX8zG}v1Y=SM$=Bx58(m(O`cnddfdJU;PGn(gkqlu0wGX>QXHy>B2gD?Po@|68 zkqqP#1Qtzrn9P8!7T8dC0}mcz#}U^4D--yFkui1^#Isf+^+{ zxS{8k&?7$ulK}GJO@8gSmTdR%LC-RQPMqs)GW7 zfFaWaibU&Bw|r*5hb!hNPU?f=={4c<5l8=__57bLEymo<_PWKD9CJW4ol)4Uclo(H>%JRu{hK+ohqn{;>Vrj-n7WVT zO3buOsDB8$K}o1dC_P?1!Ok}T%lRzbQ38R10HIf(KDpMfgKdL9kNeQvsLlfkBe9_y zW6H!yRy8ZpE@fbq1yz|5HT~7!M8~Cwa$mB7QK)f6lQz#>A7N1p1%T+U#e2G5BI7)D z!-NG@ZPq$1go%?g%Q)JqF$K-eY%SeY(^m`dr8R1>t}(hpmdXIfOXC?5L(@X~Z|Z=+ z(E@>i0J+2gij-Q&z@?>xVV=|^x$mi+ z$#)CKaArNa$W-6bGvW1r`6pq%S4G{oMHeLXBjh*^ktgosAlMYhlt*_!cSRVU4bFK# gS20!zNoT&4SWouEtKx~{b0H~X*OA==d;_c`H9&6KSX86UNT8%z%6 zFa1$hCf4Y0)_pi~Z{Xd8_Up3KTr$~h`ZdBf3dZ;~+J~$DO})#0UYv`u&d z&Ngj4c+fO-U8LsP^NC+X-1zK_m#K3ChJlQX~h x+FL*U(v=2&j8l32o8wNbuTOs!y#Lf}`78g;rZW}x8Q*&pp}wksCz|OV9{~OAqA~yg delta 363 zcmZ3;wUA5Mpovx1poxWb0W%XL6O#y|)a$U-ce+0>llw9`p>sPcyC$Q~MCEN#21bUa zhDN3aMkZ0>yhbL5AOPV`=4M{Fc?zQxcD<7iF~`@ZGTr}dXZ*Rq(t7pIV>eH!w||M@t@aD7+lRvNCdr7Xm%jqotKaX4C zCW&r~JM|1Nd0lbV4{LQPJ(X?t=!Mm$sZ*^qCiEUq{%vzfsyO@o-)qvZbJMjRzSe41 xTKjma@eSW^P=X(Do`;5AkB{k9(sXsM*{|B6S7iiTlJC7+e4giV_s&D`R diff --git a/examples/certs/client-cert.pem b/examples/certs/client-cert.pem index 26c73841..4bf36d37 100644 --- a/examples/certs/client-cert.pem +++ b/examples/certs/client-cert.pem @@ -2,12 +2,12 @@ Certificate: Data: Version: 3 (0x2) Serial Number: - 01:1a:eb:56:ab:dc:8b:f3:a6:1e:f4:93:60:89:b7:05:07:29:01:2c + 73:fb:54:d6:03:7d:4c:07:84:e2:00:11:8c:dd:90:dc:48:8d:ea:53 Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = Montana, L = Bozeman, O = wolfSSL_2048, OU = Programming-2048, CN = www.wolfssl.com, emailAddress = info@wolfssl.com Validity - Not Before: Feb 15 12:50:24 2022 GMT - Not After : Nov 11 12:50:24 2024 GMT + Not Before: Dec 16 21:17:49 2022 GMT + Not After : Sep 11 21:17:49 2025 GMT Subject: C = US, ST = Montana, L = Bozeman, O = wolfSSL_2048, OU = Programming-2048, CN = www.wolfssl.com, emailAddress = info@wolfssl.com Subject Public Key Info: Public Key Algorithm: rsaEncryption @@ -38,7 +38,7 @@ Certificate: X509v3 Authority Key Identifier: keyid:33:D8:45:66:D7:68:87:18:7E:54:0D:70:27:91:C7:26:D7:85:65:C0 DirName:/C=US/ST=Montana/L=Bozeman/O=wolfSSL_2048/OU=Programming-2048/CN=www.wolfssl.com/emailAddress=info@wolfssl.com - serial:01:1A:EB:56:AB:DC:8B:F3:A6:1E:F4:93:60:89:B7:05:07:29:01:2C + serial:73:FB:54:D6:03:7D:4C:07:84:E2:00:11:8C:DD:90:DC:48:8D:EA:53 X509v3 Basic Constraints: CA:TRUE @@ -47,28 +47,28 @@ Certificate: X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication Signature Algorithm: sha256WithRSAEncryption - 64:6d:a6:4a:a8:9f:a7:e9:75:2c:f3:85:3d:3e:af:38:fb:6c: - c7:eb:c7:d0:2b:a2:45:b5:65:be:d0:13:2c:f7:a3:c1:eb:3c: - b1:f8:b8:3d:63:8f:ca:08:4e:65:1d:2c:ce:34:6e:35:96:87: - 93:30:5d:aa:c8:e9:a0:9c:9b:84:78:3a:52:a1:33:48:6e:84: - 66:71:9c:cf:d1:c7:7b:02:4c:e1:49:7c:69:47:fc:b7:01:f9: - a0:39:3b:ab:b9:c6:d9:ca:27:85:f0:5c:b6:a4:e6:dc:f2:52: - fe:44:00:b6:f0:47:f2:6f:3f:d5:0f:ff:31:93:53:88:8c:c7: - fb:56:10:4b:3b:43:e6:8a:9c:b7:b4:9a:dd:5c:e3:cd:9c:bd: - a7:0c:c1:d9:96:f0:93:f3:ab:bd:d2:1e:77:8a:42:cd:0f:fe: - 48:da:57:34:61:46:a3:89:2e:31:d2:4a:d4:43:2f:56:85:44: - 75:ca:6b:36:e2:e8:3a:b2:95:95:3a:28:90:8d:c0:23:fb:3c: - d2:1a:73:6b:ef:fd:d6:1b:eb:6d:67:2a:e1:eb:2a:83:22:ad: - e3:95:19:e5:93:ee:14:dc:b5:7d:e7:cf:89:8c:d7:8f:d2:3f: - 68:7e:a9:74:7c:1b:38:65:f9:28:4d:ff:50:c8:ee:51:3a:8f: - 1d:9e:55:5e + 36:cb:bc:c5:52:9a:66:cd:91:4d:8f:27:9f:b3:64:80:0e:64: + b4:cb:1a:cd:75:9e:82:7c:55:67:d8:9f:90:a3:34:96:99:43: + f7:49:53:a2:58:85:a0:b3:83:4f:af:b8:15:8a:88:1e:f3:60: + f4:7c:94:b5:58:68:f1:2a:13:80:34:c2:6f:a5:f8:7e:76:16: + 81:4f:36:8b:c3:59:bd:51:dd:60:87:d7:1d:96:44:69:07:3c: + 8f:28:56:b1:11:5c:4e:81:3f:57:25:fd:65:dd:07:cf:17:0a: + 01:7e:4e:3f:8e:73:db:fe:f4:f2:c5:ff:a3:76:a8:74:46:2e: + 47:0d:b0:ed:0a:c0:c5:0a:65:d3:dc:62:b2:e0:1e:8e:bd:f3: + bd:af:af:66:84:36:92:e2:3b:80:d0:57:a6:41:a3:62:d1:a6: + 6d:14:6c:cd:82:b1:c1:c1:35:55:ae:59:49:a8:26:52:bd:ef: + 1b:2c:1f:9d:39:04:d2:82:a0:6b:39:71:59:33:82:ba:55:6c: + 97:f2:1b:5b:e0:4d:e2:cf:89:e7:26:b8:2c:6c:9f:83:d6:ed: + 4e:2f:75:a9:30:4e:01:95:0d:4f:83:5e:c8:af:7f:67:ea:53: + bf:ca:9b:1f:d4:ff:36:97:02:71:8e:33:de:e2:58:27:aa:70: + 0c:5b:de:0e -----BEGIN CERTIFICATE----- -MIIFHTCCBAWgAwIBAgIUARrrVqvci/OmHvSTYIm3BQcpASwwDQYJKoZIhvcNAQEL +MIIFHTCCBAWgAwIBAgIUc/tU1gN9TAeE4gARjN2Q3EiN6lMwDQYJKoZIhvcNAQEL BQAwgZ4xCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAwDgYDVQQHDAdC b3plbWFuMRUwEwYDVQQKDAx3b2xmU1NMXzIwNDgxGTAXBgNVBAsMEFByb2dyYW1t aW5nLTIwNDgxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqGSIb3DQEJ -ARYQaW5mb0B3b2xmc3NsLmNvbTAeFw0yMjAyMTUxMjUwMjRaFw0yNDExMTExMjUw -MjRaMIGeMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwH +ARYQaW5mb0B3b2xmc3NsLmNvbTAeFw0yMjEyMTYyMTE3NDlaFw0yNTA5MTEyMTE3 +NDlaMIGeMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwH Qm96ZW1hbjEVMBMGA1UECgwMd29sZlNTTF8yMDQ4MRkwFwYDVQQLDBBQcm9ncmFt bWluZy0yMDQ4MRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG9w0B CQEWEGluZm9Ad29sZnNzbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK @@ -82,13 +82,13 @@ Ztdohxh+VA1wJ5HHJteFZcAwgd4GA1UdIwSB1jCB04AUM9hFZtdohxh+VA1wJ5HH JteFZcChgaSkgaEwgZ4xCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNb250YW5hMRAw DgYDVQQHDAdCb3plbWFuMRUwEwYDVQQKDAx3b2xmU1NMXzIwNDgxGTAXBgNVBAsM EFByb2dyYW1taW5nLTIwNDgxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0G -CSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbYIUARrrVqvci/OmHvSTYIm3BQcp -ASwwDAYDVR0TBAUwAwEB/zAcBgNVHREEFTATggtleGFtcGxlLmNvbYcEfwAAATAd +CSqGSIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbYIUc/tU1gN9TAeE4gARjN2Q3EiN +6lMwDAYDVR0TBAUwAwEB/zAcBgNVHREEFTATggtleGFtcGxlLmNvbYcEfwAAATAd BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEB -AGRtpkqon6fpdSzzhT0+rzj7bMfrx9ArokW1Zb7QEyz3o8HrPLH4uD1jj8oITmUd -LM40bjWWh5MwXarI6aCcm4R4OlKhM0huhGZxnM/Rx3sCTOFJfGlH/LcB+aA5O6u5 -xtnKJ4XwXLak5tzyUv5EALbwR/JvP9UP/zGTU4iMx/tWEEs7Q+aKnLe0mt1c482c -vacMwdmW8JPzq73SHneKQs0P/kjaVzRhRqOJLjHSStRDL1aFRHXKazbi6DqylZU6 -KJCNwCP7PNIac2vv/dYb621nKuHrKoMireOVGeWT7hTctX3nz4mM14/SP2h+qXR8 -Gzhl+ShN/1DI7lE6jx2eVV4= +ADbLvMVSmmbNkU2PJ5+zZIAOZLTLGs11noJ8VWfYn5CjNJaZQ/dJU6JYhaCzg0+v +uBWKiB7zYPR8lLVYaPEqE4A0wm+l+H52FoFPNovDWb1R3WCH1x2WRGkHPI8oVrER +XE6BP1cl/WXdB88XCgF+Tj+Oc9v+9PLF/6N2qHRGLkcNsO0KwMUKZdPcYrLgHo69 +872vr2aENpLiO4DQV6ZBo2LRpm0UbM2CscHBNVWuWUmoJlK97xssH505BNKCoGs5 +cVkzgrpVbJfyG1vgTeLPiecmuCxsn4PW7U4vdakwTgGVDU+DXsivf2fqU7/Kmx/U +/zaXAnGOM97iWCeqcAxb3g4= -----END CERTIFICATE----- diff --git a/examples/certs/client-key.der b/examples/certs/client-key.der new file mode 100644 index 0000000000000000000000000000000000000000..94dc253a2bd214f1c2c9a99c5d7c649e5da5ded9 GIT binary patch literal 1192 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 diff --git a/examples/provider/all_mixed.jks b/examples/provider/all_mixed.jks index 706db398565965a8d84e25d8c09fece030c3e337..bec480a22979f5ac0a8f43287b715af27cea1db3 100644 GIT binary patch delta 8834 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 G&Hn&OI)OO= delta 8856 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 AS^xk5 delta 1976 zcmaKsc|6mN1IM=^)oMVS})sFK=a|>N8mh<@W(}WN1EwY%oC>r zqU_$t^|`HA5`VF@-b-gGEsn0-a{$JeJ+hA_!#oBlj&Yw(CW>Jnc=|M2JdrPP-*mtQ zc*w4!tUu|9A8n^DgrOG`VVJ}I)Hc9)%=jR-UL}in5K5H6H3zom#CYXAJcsG zzHEq=?Ih#+*Yu4>tZvoKt$hp4uw1sal%HdUo7_&3zIDJATCn&oiGRK&FVm95H38|< zxyr+LtlE>^#vdooY8AK}P~DIiCEB=f?zLarefR^O=P^{|8JEiSRXL~%-lWv(u;u5D z>(6ePYLW^FR5;5i5p|m z8^**vDr&ibC| zwK^S(v;Y36e!~`F;liBjcD2_Pwu79ON$?{D5Shv-$&fFRloPqO^RviliKhz3J^9oR zug9{)zUYLOp*co^q*;hQy+Z)JPY1CS+==oK7?spX=f zu7g?n_Egh-Q@VCS`y}yKYR~DH*li>2#ded0`HgYo-Vy*}v$`|;ZTk5ymQl!w_4q7l zxx^Qo)p=~Sd3=~TNmqZOFlRI4Vow^mJ4Ql%DJ9K1t*E#-cIln~D14$&k<_7AM1QWm z=pj>H_LtH_=WNyC5VB}zSoz5$AS))P;?Ibjr+i0E-vb7`-&E*@lA7n}56<|+H5EE7 zHABWq-4A$|7au?;J_YxNIw`7pS_dx~z!17vx&Cu+3k1>?5v5gM@kzN&*WiQ<#TdAu z$b(sVNUS*2El>B{e%1xNI2SM9pH^C#`Jrq1jSk5c;B6%Y^o=|ZLX6NZ5<1TMP>=T+ z4*r0k2|Gu&{5cO&Lp?t}>TY8`x{e8Wz{Qn$0=M_a4hoPm1v)DFiz}L@bUnSZ7tS>2 zs&g`aYt_0;oc>rr3g~#@fxjzaC48b$rztL#C{}_ZQd?p{ED$o9X zJLA>q(W=4Y>C2RZ)$AvNDD034f2*svN24Pdy7KG5Prr81)t7p)krwWX(;{C97FWAJ z&RT8Wj`vB4() zTVL^o<=bKq=P7T(DN*#k$Kg#7OJ z9mx>v$kCM3PQO^-wW33owN35)JpGIX|Aw-0!4iJc0o1VIv~%nRf3KHk}82P{EF+lmiI==tA$8Z)s3qmdb-be)I7JL+S!IVC|od7_&_{d9wG v6M3=vT#5!de9gdh%bh!i!`y%tsCWfhItCHdgbr^hzB~f9S4w)cs6YB|x(K@` diff --git a/examples/provider/ca-server.jks b/examples/provider/ca-server.jks index e4673d730c20839df4ff92443a0118d701cb0dc0..ccfc2bea44f62ee91062251d6543d5fd2fb727e4 100644 GIT binary patch delta 1994 zcmV;*2Q~Q98`T?-8wH7(a!jI;AR2!~D|m>=XNe^y#{6;!nZkK=Y2%O(dApF$8c>4}u;rknFyar>(w=g&!@sCIyW4gLIMDA|#qHf&!K>f&x3B0|Eg80u*IuLQDqd zL(Z>!0V0rRUHx#3gRBzLAw0000100v`WEpl^V0004rnQ}{*000F7FoFdB zFb)O^D+U1s0V)C!0RaU71cC(WAs^uU3V(;xIU#1rhnI%&AyM(eZ1>1sTi5B&DM+BE z-ip}$9by>LYFlhUJRpa-!=cm#N-d&@tEp=)<}`|xe9MR?T|7ifFxT}qeby1@UC9i| zGyd4lI%=L-y|yb*SR-bh`nQ`hYM1LcO$`eTq|FC83C9{z)^|W9nGLS5?reowqkoOS zC+QA*c<^AB^PQkaNN|G#c*-f9%M-irQx1rkJDh8eOgyuNuH!&Y?-$sko%j}7QEWcC zM|-Q!xfG+Fen>WDp3=zuTYE5YGo$nGH)E_F_8UGWW;W2w`r1sm9HP?0t=ve44ph%A z_3g+tggeNiP6J)P8hxV-vj$Y_mVeb*-lK z+yDsT`&%}n!8H>)DC5AaBMvs${aU6Sk>my*r59^XK!bPsfQWm152WH0JXPMlrBUiF zXXqC_Y*-HHe zTt~Us6WgC@pA>>Rsk3G`8Gl3ZxRG+pJ_45PeEp?+;3!MXh_CyV0%FzjBD*zX=Lh!s zJO>2Bf6wB*8K+!aKk)!d4691`9S}PIb*{v9XoDlYxT@a^=#Dji_qBBIFZNa6DBM~{L99%KNve!;uw^~jysXdjXp)mQa#>W9~M z(U@6$Sr&jkDMe<4_1r?95PQa7qUObAGj4iyL}1JLKeQEG*NZeDpEn$Z<|%Syg;Grs z1$eYHG1ln0IE_{qw10A_#T|GbPSKED1!0)}FRCfW;tgR}sijlrT{SC(Sd3F_HcfA^ zYr5m3f4C#WMCOrxr1BkxE)U9k2Gm(1Gw^{^e&-s)X3=Bk`nmr29;T^(ojipF<||+o zlAT0zcxOJh(oPy2i3Kp05YBV=;F));g}4ZK4h#J{AoyY0wQ2I8%6nSo z3IEVpexhr>#=QfMzL&0>AcCDg{Db#X(Hf;fDcF0*L}n)+*4v9=|Tp~ z8BY<^H!b|dBTnIyqncUezz=UHC%i1}`K>en?#s><23j5f(UD8?D#hF8{xqbeeH~LH zMc5Ls<~d3@h?|I}J%ZR!$NGKn8Ty!FTjB@x7M3=CL>8!=e*N|XOwgGx+pZh*L!vw5 zB>PPX`&W2^_zJX=pbv)MhCDx2lbHxI6fA(w+ee)TW|BQ<*UGGrPs(XQOOxLStQs*g zF*Y(WF*h_hS{Ds6H843bF)}eRH#9j~lkNzZvpotA0u(HO&f7&8j%NZmzBRr$+IM zbLI&O*Z;hpjlNR zvu)&eUhIDG2@{T)n6lx5wo5(_L8c7NNtu4+ipw|cQ_qH7sV1o90VP_ryd^d9`dVDh c)VLO!ER`eyqx_F=st!>7D9|s55dRI2XqmLE^Z)<= delta 1968 zcmV;h2T%Cb8`B$*8wG$v)`1R@AR2!^v!c0(AT-tA#&$tVJ<-(NMGvquVi6V&AbFV= zGmG$rNY)P5Z#=3pL7@Q;2#cu_NyKT2YsAAd;f6eMl(WGYp9x#L0BwICtz~r#$pVZJ zL};40A|#kFf&!EfTfKH9(X^H31pagsK0dp&)#>jE% z#{{hAzg*jS>dgzcU|p;qswzSKoh|%8GBB#7S+Mhd%RPk@Z_Z_GioE?ysr|=`lK9-u z?)vH6%gkyw+%fyur$kacIS79lN~5pE|3q~*=d@P6a8uuBlm@bII;M6Z@b>-}!gpU= zMY8Up1IMCyeA}W`{?1ne(k$nEqj6-nDVUwJ1XPul5 z*Z!h%djzyllKf@J0=8x=#08qRb8&i(vF~W*Z1!uZ9lQ+?zWMJP3Mr0fwYS5=581nza z0TYntx*mvi{^7QjU@U(?Mt@zP1x67)!e)nASqk4h)mU-qxgPauYqx0|PRB*=(8AY0 zWn}=yE$qxgo^h@zt*(}q>Fw*Q&(>h1%!t$>GnDM8xBsEH^8AiA(Ur_db6E9PoYh$B zet9Vfk%4Pn9A$VkLB0p-??_vJ;`~j zp(qw~2{l7fb%d6!aELb%V5x|x*5&T4z|<>Ji`|0BU(-Yg1R3&6J zd>)t{Q(~(E5{$Jb1Z)=!5*;T!edG95M1w9_)17qIHtc_imhTC3@cVL*_SZ&U7ndTj z%@1O;$TX<>GlmJw^P9eSR|!Zd^|K7A<4-9jrEGzC2ZiFymmLY#il!Sl+5FDqXts+Z!QZexqaTa{g+1EW~{FwUzytA3NwTaEEw$3R*D(r`5 zQ~RtKMe+X4M~5m(D0rWPNir%}r|%7kwgu5+!dF#SocYkz8cctojl?Gx<2w>cen11$ zxKWl0VM{-ON~fP>EFioCY`TIwNQ(5SGx+teuXlf$I*HNQ`+}s2e*Nj-I7Lo^>N)kJ z!w-ro4T6ItAahh)@;ws)*(2TlsdiT8l-hX z=E{CRim?}X95nJP<1=LvFI5~|9E)?6AF4V7lo7%yrnb#i24R#FvnkQjUWdT8pa+_N zD5_uA!H?%pe))jeMm#Dy{G|Ex6KQfhsE*z?lzz6m-)zf_2R)DZG&)nLIHKTh6rgM0 zPgd1;KP8x2y+#y2nWBr%;%M=yi4TR}{RhTs`uNR{S$^(*OWfSpY**@%gZY!22r?8V zjFb8K^d7STa+FnPZQ}Sn+UfL@;Rvi6FfuVUF)}qUGBjEj4Kg$_F)=YQGBq$VG+LAJ z2$-`!3J(GlCXAE$`Sc#M0dka8XKmv6J=*E?lVS{Ce`4etC_J6gV5wEUYW5)V+UTJg zm$8s{g6+q5DN{2T5MtoHlN-|3p@2gjWbs0h?6hnAlVE6HB<5W>918ujQon$&eg`3JFCoq2V`UwL^@cE`P+-;jXv2MHBdN)p-U_ zf`dz#*H%Ylnrdy1dY$is4{LP}MIqae1=TOz7?Lo^h*}NgtZi Czq&2} diff --git a/examples/provider/cacerts.jks b/examples/provider/cacerts.jks index bc3211300b7825d97ba3e3900a6d3694cd65fabc..d05f0554eca04babac3613ed3554cb9414fbf919 100644 GIT binary patch delta 6481 zcmeI0RZtw<(ynK4CfFbWhTsz1-3cDt-Q6964lppdLkI+i;1VhFiIvvjmh$q*Gr*-Kp*v4rw@sLU|>IHC=p7@ z8s%+SK^v$-yylMW^e%c;JfJ0JUnOX8|BNQ(h|&5k{tLJ;S@Kv0>NsAe+fj-W^^e^V2o2 z(8*Fsj^V_Vhf*)jQ+|gqW;=ey7%&{hV>GoK2?T3oWWDi?e)&P$HD#HGE}JtP>HXg$ zQhHY= z(Tzhyz-9h*6V_+vZ%*E)TAFa?r7bbJc8r?y->Tx93Nd`cVCvi=96nX+=C#Bg6U5!A zhg&YbEnlN}k8omqycpDO1u>*NwVzF0@sdLUZxi~tJ$41>iG}6kmH?e=^%6kKk40@xJp9lZK}lMI@Y zY`^bNYkuE19=jBjseBSt78{j4(3P7?C>7hHN;9JLw}IeN)QV{_?7VCd#e$(ig4I12 zzN#m9{4Q{_^Z%1C5P=tYBugt=zSIHq4#%|sM&6BeJTmN#y%?9{z|SVklf{B6Z8Hee z^0@^m*bs%k@R1zP!I!jM#zxX(TR#lY6k03_T(WYLH&Lai+7^sce7SdI0H4m4X^04+ z7|o1eG;Dl{J8Lgf;MB%d6hBQ|Z^@!)6B|VmoX=}%&#c<@5vGYf{ColzlfZ;*l8~uU z_8FlwnP|-Fm(xD(6*ci_sue*Ebob#`-Z+V$r{^QETdYuxH0QW#7Vm(d&#zEJ7PGp3 zaOgr{{EtoQ)*my)8v};**z$B~J7y@+M-Jn%Z8shJm+iTV%YL$3q8$!V>Xn^~jmp6+ z@7ndNgY*z6k;szYF0ws)dV7ROu^!d}{EsfK(1)b(QaqS%wA!4~!%UzN-Ghvh+mQ=D zPr|00{MDb^zM?@KsefcqS(Fpb_79WCx6ICkN$t+|`nFCSlX*WO)aAk}sq1!Ui+1%i z8X4WF=1Fq5Raa~)d9m+R`N#q((mhI*uBEz<^E-X|I`ap0X=co7$KuBt(wP-L^+8N= zU2ls{Gos;q5k~bEJ$2Bn5n0K|J6`JmhPss(nZ7FEYO3s_u$M%VkBP$u&o`oAMqNt9 znzw!J%`yks^_R>kGXX_Ta_Ua#R1%6?ViRq5!jCTEi35Ci6Dv=sgS(6m_U8&evBG%V z93rQ@aXk)&z#r(H_dg;{oKxV=r_K^Q7{#m;%=A!UZ!$rg93`PjPPAFEan~1X)hmOx z=v|Tb7d<^Yb?GAxyMz96rUJtuABXl5$Ex6KU6(o1sba}MebDVJKTC<6Ix(B@61o3S zpN$T{sZEXMi{g}Zqa!OFHGmR(N&EC`Q=yWS&S4;DK4xaYTw^*?EiLYVaOxx~Cu5%a z)6LofNOM9|NZ(8_9H+A2Dog|q3eb|e1K*hPYi^q<9>5Ho1)=Muie zShCW?#v;8bVahevj@jwbw@J|;SMPOBts^1{-<4nzxw-NBc0KFr3=D?}-RTaj zz1eK6to{uaSJ}b^S;yvpT^4T+C_4wej2ANaI}9kE{3qn_&%N5FKv4X$}{UK^il-d_bWWzDS}x% zFhW+bjae|cksPrVwuX6~mW0DiXs~BU{j*=f4(%hgw7Bo+nS{NOR@wqi5$XRG&5g;p zQ^5bM+k_~mb%VkBRPMJpt|=p!e)REeSuWaa<(g5%8gy|4sWHJLZB5eb3V&%`B}E{- zaAj&iz-e353Sko1YXYN`eOgl z6)skmrl5MBjgk!VOfq#UMH*Y@OuL6~$2WRq3;lsiT3No7RWeDQ8ZOs;Js7sSruHt5 z1b2ZJi7(_spYTnH`tg4Lb#qXe{(CMpkx^r;z$7d4q9I=W#JVqQNpA$|uS$_Lr@x*o z#38}DnvnK?KEtm_R5+o%PRQw!Aor@`@*_X!#HRy6yNe3bZ`0A~G|e7Z?BB42QS$D{ zvhp&*Yomg-gA~UDa!pihr22oE7`&`v+!^>tlxg2z2PW5 zCCd*t*ZQt3-#8yDdpc@$EWp9=f*dN*i-hdg|w>hb~rGUPpQltZ?&y{Mf#=wIf~%=P#UI* zYGip;){dDDvzNMKBUJJ3Di@ua(17T&7^64ikd~MgfSKmGP6{d)~e$ zi5cpsy%LFh($gTBTG3lZ=XMzkOj75`vY_s&G4E5C8%=o*8hd0D?<)B zFjV7-QkfQ$m-)e^WoWfJNIiJJDvoN`9e2~RE}DRZHmvr-n;X1hk(Wb9$=}P?%jgVP zVo9Y_e*}+byI=c+5!(+GcYh87R_Ux!V$*mIU?no7?ahYiJXcdn)wim|=xViu$%kK6 zWl1yo>O+k=`r?isDuD_~6~=Sx4bj9f5t)n6Xvbz`MS3fH3`^C=XEioNNZWI}!)iYQ0;BvS*oBnTd@kn%xx92BC3jZbFA zLzyv4GVHoPXTRg-=Bki*o7I`*DX@XkrH7c7MWB>Cx?COF_*89?fn;&T1(vhho$T34 z^lH|0uR5`+oXgmFgFf4BjxoghV;m|Q^{8B!v8wS$ zFt=&cT+i}waCp1Qd2O0~NEj;n<0?%j^2K~tnPL8E7)A4D0mvLs-2@5LM$5Leg)A1q z_n~jE9Wd?L#XmRJv*tlMq|>WylR=w4)psj zCpg>H98Odf9;*DYT?U&R>|cS}enN}Y!_aBZ+Ze{NLO%|o;I~O<4X&5SQ{-H}R(8$a z9ON*-Rqs!zGqGhcc%M8_>o)g}omw&I zDCZT`hZH_mU`K}ed4|%LblY0b*;+IB30~(1;HVzScxqL1&5ybRAA~@jh!ue7*34lj z#1s`37ay%nlM&mCiw0%m(4=6gyFKeDz|?IVdwBS1X`lZISBWK9u4)%S5i9iz5WQEo z?gfl{-+Dm{J8#y^C*?KmKlP=49}4~jkZY}D@?D=md>c94fd4`1`~S55e?{y6V*_Ql z{{f4011hW*K^3}V+p`jwuqRI|>y#gW}=D4;mK zaHrY0zZNb~Q14YG1wb~Ib&{LDVA0U;ym50A3PJNvy(8@GUGbPfSEy|=B)>`EZK8vh z)=@3l{U%WsT3-eDc@7R0;p&Ip9j?A%`OIp|e7H~&K8kn=K=DjBX*`$4yGw433TfPb z4QWri3~=jE?1xpcx~;q-v0!pah0c2*r;EA=_+gx?Lf97xVmpya1neK5ZP>+U<-i6T-z3YN_H;dDUiR7{$I7q&3V!EJN4=4HzaY(U5Bfpa~|n3Rc)N z@}dCpHH{o+s)`hGYt#|HR2u_RP?>3IrGx9X5gCkD4W0z>^&M9xNi{09n2c1OGtN2P)B z2^sz05b%Kpi}}}r(Ts`~C2;eRPFO`T(Q%pXOG}O&X?#d1@3A)3|WB^|ytPt7dj%C39K z$7YCSk2|Hq1NPf@Nt0-IueMKo$-|Ukm7k0ZG0Lr>&C9Fsjoy-Q=oDjfwkU@=uN~Mu zkv*|QrU>voK~^~HN@MzR+_F)jMec{vbVdBlcFPLCiM>u#ykk)!VKNH}@nH+Yc&cy> ziE%IlTk^&3W^0*$Xe=y-Tef#<|?4Hx}ui&Xgxk+3WqE1 zoafDXm5vphRc~K5=&i_DM46JS!Eo`17mhUQ@4t8l21IE~_4HvF&0h<;>gJQJM1+1E zwIDhC^J31opEBVpUYoH+?z8+9>V%$cHUO}HZ*-I%hs0W$r2-W==`iyWQglep=v9)?Q{b^a|$RJSS;2N6Y^S$8?hNj@yb4Z$i^Mw1K$AgFi zbG;s=291FY>3IG%g>QlmZ!Vwkr#9>8q<^lIc)A}D&?Iu!bSf!ml{~7DZEWc`y?tCK?s-ums2?0U%H_GmZ)TonI1sc_{7p`_!vZtgil_0kdEDQesVGI`z+}{idsebkp+z~wYpZK*l3DN^Q)lrW_|l} zW`a=OUbj!TA-*re)cE823_3N|&7+pc-^)0lizYGZ)`N{z!zA?RA8pprr-(to5LJmp zuhplki-G52-*Rs`c6liF=VQ>f0g%nynq|XJip0*#&bm6=2>#S9kGFHl5A(Ywh0w*C41D^0U9p}soGNYd=TT?N=7+P7K^I?m} zsvJHQoT|VKY&Dqaa2?d{K&yN7Bjx-ve843mOmw$czLA0#N}d;YcO6-=7zKgY_-?FRGVAY+kw*J!6)jEUBx$ee&;9idsx(VHAs_2}j)m-gfvjV{E0^!gzh z?eZu~=q#5*>ft6oZ#pi9c%-;qn0AMEkOwdZtrhIrJjD6q%LcqJRG&osJug)xYG7UQ zh3lc&j*Fgh{#0bOYOKqD1ckltE{%xGa~P|4euMbJ_t;J2XE(^d{!I}P>2A#l!^CvxA3<| zVZUhv(B%=69`6^HwU<;qPwo+MYVV>f7rP?N*`5lliH ztzWpjPBnBIS$eI}Q~gQCOBKcaHYYH5|D=BU>=RfO&0><{mcT?e?hLEa$c-pi!EyhV zx#g$l2C4RYnX8%h>d6}8{ZiE9u3xrI5WnKnu^9#LqzGkS%Vx?D2Z_#4!!|=&iTk3t zHlK%%Xibo7kYCzLLlSoHx6;&@xCwE5M1*Q6wPqqkP({F&YHNXDPjFfWQ~iIN4$SOG z|5;baY6@))?QXb+WoU#shDb#*E%l8Iel*{)DMZO6ClmSo8X>(H<0zWf%{b#DKz)gA zP25n-2Ge}jJ9|^1P`Mm&fE|kJ0ji{JavofS61=?%|GE`cD;IBY-xu##>64*?LHj8uR!e?*{q85zd5gYn@?1!@}@UloAp_GA-qRl3=pRlEE8z- EKNV#XF8}}l delta 6512 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 E0Jk2Uw*UYD delta 370 zcmey$@s(qOe0_uSwZc{g28I&`jYkdm*toRW7+Dy#m;@OaSs7RwH)&gHF+~JUyC-=5 z?k(Yst%`d;ZaAd!cl%_CS#{eVZZ_?=PujS$MSPd9uG!WJUs!3-{Ua~AIlW?9~ z_s(gtLEf+Vw~r-P{w`J1_R}}dcD6T^n5*WX!Z4-Ggdt{5^gTOY=RJ=n-oC#~Om(C3 ziv9A%Dn0qI5z#*Q9bT|3MYWw1cJ*`Sjw8yg)sI)`ySiO$+n?849Luj=tywL*MNF&ou~RsUpf~`5 C9GeON diff --git a/examples/provider/client-rsa-1024.jks b/examples/provider/client-rsa-1024.jks index b9a3447ae5a4b0b41d4b15c361bbb2860dbaa40f..da535824821359ee391979f6bf4f5e8e82573a80 100644 GIT binary patch delta 915 zcmV;E18n@J4yF!}Bn63?ayqS%DI9;=9A~zxyjN4(?W^oQX4Ui)OdXG{AystW13jTT zlWZus+pu`RdBPm8^hgX_!=7%^vwA$=_V!Hgj&uJcSD0$qJO$i*NC_YXw=)uZdS`}_ zuY=EYes>BGiaB+3P{2gdqUwQBM3yH4D8QZ8`^ln@K|ZH%zQ^J0pcYEcD@K1c>=2~f zw;u_<^{KUA6HGt~sj&nQ-?LIGlrmwtk&ln*AC>ej!wm$rZ4U@Mi6}0=oloyTyJIp` z*0mdUmyP1Ch&PMpQ=IY~*0TRY0B}v~B;y10|DWj^_A)vo>Rqq~>=hB)J!Rb)K4l}S zmtdr7T7Nd-EJy(?x7XfwzVLr^BuHkC5F>kXufd&PG9sfohv2tH4*nOVGU%VwaGFaf>U9 z4rHze82g=m(j5b9<(Ja3N}sFww))du_Y(TzjltZ}xBD=x^kK-AKPSF8{xkMY&??HC zJf7f0c!u$`E(G%NQsRH_BZx(~({|fbrD?EbAm?Dlso+NB%MShO$wxDcXg=dw%XRv{ zzRZ7-+1(^M*-w{w&pc8~`_ogbj*4 zaoUqHy;d+810Q8Lhu=`tvGO{mXCYEAZkUaWC&7)}0H0;XO70|TRQ@$UH zeu-WkkUo>s0x}dqAMDRbAQXYzt13Z9f1XlH(k|1F+`&4ZItzf>tdzjVrC>B`|fysOD& zSA`f5{}_%e0vcRKwfN@@b&6Lh_BBFE_^bsNnPiGC&5Fh};^AeuW2Qf;$y2BBd!TZ;(Hmr5`uKHm(73Mp0# zt~<|=;8f*;5V1P#53P_`K*Lgs+7ttSSBukZPp>AhYlMw&K~obI;A}ua>*SOyr5&F| zW=BQ3Q_^QA7091Y(d>Lu`$T^*Y=BxAQb|l7(^pD0jDjMAw&EkR!W;O|IE!}4ZSfZ#Ue5isO|(7`^m7A#kBwtPW?{>Hy0L9Nj~ zsxH;%p>WFllJR)M#0OF`JYz9ptIMPG_WKKa9Z2)NK4G#r(|r>k2!w(TMPPHmOiq@+ z!1WHaT6dGv0x}d7n^6_F1SrlEJ&-Gfy(HJ8>ASX*83VQ&FfuVUF)}qUGBjEj4Kg$_ zF)=YQGBq$VG+L8=1);Nw1eO656q`{Mw*)B86FrbCg}o%#qv^Z0lQafie+a}o8s>3w zQ~_I>9{{J)S8SnSF|(3#Y2%`NGKhCTE{|jfMeqp=>E4c^Z|I)!%&?V)o3fR2&+aV7 zRjwbEsANhVFh91Y?p8@F4F-896L)oCsIgE0w%N$19t5DCT^FuHy~Pqh-_lLSn7u&| p2+eO)xz^j?(i-QaUl#f26(Uwm>SALXpSpXnF3lrWFnx2-;hNtqtvLVy diff --git a/examples/provider/client-rsa.jks b/examples/provider/client-rsa.jks index 14328f23e3f3ed37bc7b0c129ae54c8a4c550a12..dff623fddbe814400766ac62dd6acc38280ccf3f 100644 GIT binary patch delta 1652 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 diff --git a/examples/provider/client.jks b/examples/provider/client.jks index d0477348765cc5cc2e4614706915997eb71f4af4..5ef402cefd63f56304392fc22c4aa16a75cab81f 100644 GIT binary patch delta 1978 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 diff --git a/examples/provider/server-ecc.jks b/examples/provider/server-ecc.jks index 77cda05e368a0d5e255e4259ed33dadcbaa0befa..118ffb8e3777be71fd9941cac57de46396ecb9d0 100644 GIT binary patch delta 328 zcmV-O0k{6R2e=22AAgCNazYyb0077^fyFQm1_~<%0R#am0uccL1powrvK5xBhj~z* zI|T*O>ad*HqcS5`0dHA)=4ou$F`CAt#c|xx`|R!K5+$@xYbbxY9ywJ(ZN)!Mb{jUu z)^QGW{c6zrRxJeqxt9rGoG2+EU)elc>4w9o54Dd)sygcHu0Fh7a&G~h#AdFlRx0nl zyz&?J+BP;eSWrt2f(stEZN7ZJ1A8&Cjy~)VqA!VcA#t1-4U8e1 zoQ$28QHa&W8{h?(QL3?Y;6n{bOgl=d(+?B_`GhOTO-p;FPSTgNJfGTptGj~?k=)-M zFfuVUF)}qUGBjEj4Kg$_F)=YQGBq$VG+Ho$kCPq&KeHDCNdZ_OTb=Z27l^?s%`-iaWF? aIO4HMv}Z7bazQYt_4huhTQ*=<44uu|qmLE< diff --git a/examples/provider/server-rsa-1024.jks b/examples/provider/server-rsa-1024.jks index 316805ce0c6ab077980375d5ee36c64b42f2dd5d..f674bea3f35f271838606d8c3b747212d90a5107 100644 GIT binary patch delta 1146 zcmbO#HdSnbLVf4VA_qnW2BzHxO-$Pj_}I9#*%(tZjc zezuX{^(@qH_oMzS?b9xMf1Y1^`Pc4%lDv;`TTF8IZv8Pck=>RxrjbKMclp=un_FI( z$*h{a>fhSzy$7`a8*5nPrCD5Qh}Su}RBFcS2gcL?H|^u+nA^4^{)7CgGirSe6%`-1 zoqWxuaO!=qh4HPHWAyw)6>n#%3#9-P>#b2j4Bsrd@|)l-tIw(*%1Ea{XJkc+tezPL(d?lkdTv-@TQ zuqiE8smmO57FS?{w@ z>d{WuexU^R#}0q(mD#_Ff0gEPa&QG5%XSX1Z0xe1?Rx*zvAKy~)p;Uj*GihY zpMEG>xxnC{zsif_wRZRJRlUfZy{19;y!2(!8Rx%Q{+_0=x=uDgd$mgYHa3Gk=C4mC zb!*LEV7j8R!g$sR%oR#Bd$jwC`UMfYX1_>^DA$#yn_Yxg4;TI^6Vv!Q-Rrtd?m#n;pjLENYDwcgtp zu`wf{rD5UN@dPc{?w8SbuY8N{jcsZxN{yiRaU$o^x3E&8iX>--Bz0iT@(z z&(~9r_$dq2+u=)APF%6qLyu+UQc(rT({=)m=(1v)`-&f|Uc~AdsY1HJ< zyK|+%k)w~|^&=07zfR7u&G(!zZizbT?-Ue?qHlKtOiynJ@y$*c^i zn!7>IjZJlZ3K-u6WoP`q^MUKy`(5AIOyzt-XP$m5G#uFg=kpFfueXG%__XGKmuBH8L>-0Wf#-S!OLJ5tR(fjaG{^Woo9* zax{9ma`Wa@?Us|d+2ZQ^o&Hu`O}9VtwVL1XWVyZnbBBWV#%;Z4J1TYLgBL#STvU82 zID5zM>=n0@{?&T=7#;k1=5E3y?=!hgVaGa5rhWgfyd?cY=MlNvcTziCHr{+4mC1VG z>g}DE^>b4m^Uv5I9#pW~Q~F8^-y46Q>1qpliWaWhztXC#=Ja!3R;d^sQT^u(tPy&q z29^vAEW8FyESv^S%tZ^BnHZUHxLKTiBObp#WY@!?59HTq<9Akp{l_=%xp_@&o7BvT z$-2THmj8%dS@A&Y?nk`^hAgTrn_|qD{Z*K>xFdN!i|r?CIo_TlJ1%-Y>kI2Wwua%? z>h6@v2}%Fz9j(jPMf-i;jL514!bGI%UoZd&Fihb8uwp5_I;4vxrYUHyxf)w o8$VwT-6KEMTJBpQx9BdNXs-gZWl!>pEgr1h6|BnniDmIa0A7d>wg3PC diff --git a/examples/provider/server-rsa.jks b/examples/provider/server-rsa.jks index fdae9ffaf7353eb2428e4ee5a6ef52d179782ba4..f2b99fc321836590040ecbd509a464b364546ab3 100644 GIT binary patch delta 1993 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 J{-0iT{|(RC-!=dM diff --git a/examples/provider/server.jks b/examples/provider/server.jks index b5f1268c547cebbd54cb1ceb2398434b06dc8c09..23d05eede9bfe2e3caeb30deae8b3be1b53e0f53 100644 GIT binary patch delta 2289 zcmaKt`8yMi1IKq@Zj<}?FlAGWHfJnDbQtAk8#9rVTwy8K%5s$Z$`x~^oH-^mjaVhO z99_yyVpyW^QJ=nlK;IuPdEM;Tzv80a=iHe9yDD515mi zE}JB;2@IEi1LsrS6&O0hxSaEnUF+iJ_k_KiAx`Q{k^$O^lY;Iz-S^^m@nWh9dA}rk z=d#I!a%vwRJn!Xa!r`rNacf?C&jh#Y9`v>Z4LTCNIBcwaVu|cC4HmYKQoY9OoppwK zoZbo>xTTi3oX^+QbmwFEj{U=TEf7!Mz|@K91ahefr;2K1(Yu1te2Z-DoTIt-!KtMZ zm7xCWIa??QL+U{dpKXuI)ly`b%YXPqRP)OYKr=85?zG3TPI8HP&E1n%Jf{lrv9zkm zYtXSK;7O=1UNv{hddQFY0%J!w%zoJs6=Eb_@E9V?OrM=+K^j##@^sR6nw}aBtRX?V z5g|&A)_Td$q-j0!-a2H6Q#S49%7#WnNTjV-1#wJlC+z_*DP;CswAjEg3>jc_L<2_RNJ2ss3$b zW zsV)0z%WmA~y2VJg6nyB2TY_9(v!HQ?_38Zhi!Z0vL}ow;HsX7mS=Dg17Xi;b_zr;& zy>fYcgQS6Y*1MJ!moCsP6f&OZ*9tY?zL?l8!0djw#QEWNb6G~U-{PB*CdcDlrNa5N zDKo3jA5K_&}~ zwX5eU$o_lsJvRsDI^Tviuxu$?e`<%sF3}dAuH(mXPUa+B?7Z zSCVyr$YCl%Yz97@Zwl)l*+51cmQ3aqL*O|V5f&?;+dT%EfiXJ^zkWRk!7{oZe_9!p zjXxFl`m#-^Q!JZVa@W!AoXu(%j7V?NqU>ox%IeUW61-D#Xl=BhS!Js9NIWX*zHw+cMmpkM;l`J!e|9mFCt!2DW%~`n zTy-|UHd!er)Aw_Xgldt-E`RKtjp@GEE92#7fsx?c*k24g5;cj|REtYk-n7=a9X1Nm zBg~z!+27Y42DZw^*rD@7lkp#UQ z)mF6@XF5tNZCY+xrMJ-JLmnjShNXj~TPf1nwbAL4n{qlnf54&ns~0iY(yad)JwY!{ z#Dlbu{;Vc&XgotL7^m_bpPPbtb7XOCcd_0tQ3*Be2;jwQ{pke&@Pbh>Jik#f;H6?P z2nhO1G+V(M`M<^{W|9SSGmH6PO@l(~z`s|ot1s6}xvNmI(p2g)WTZS9(Eet)0+*T~ z7!W!>5;S}i%p5i8ktO^`z|0cW8k`ae3r+B|^`~YV z>z1%o)B9myao1qQG4EmV1PX!&v3@aV5pyj5zQa`o0lOgEJZrSDr-cj3gXiA^$TC&N z5Aku)W)&e$oVd?f{au%0f|E*<|9qJHYV?MHL`q(6<4nvGE3BAVh46r7UiAFkJ_C-! zP#mce@n``ECo)(ey< zpP&XGkO!y^5(ff#0X(-F*M&0nY6g{#{01a07tP>MyYDxi`vip^#1y7_ctGC`mw`Jp zYpVyj;TX@2Vl9hcvw=m})78(nqE7YBf0627pHj@cv(?nslBRUYAzF$_ZkvA^tvpW8 z2fu0?s5%rjws75RfK8ZA54b<+WF~TalpJ>n@vMD`OtUxKlU~$+k$wDn>w3@Ak?YCs z4R0N=7E%Jb0w)~1La4Vo3~g|w8PNYX!k^G2AYKJ9WF(U_#)`C^VJSFdN0ha`3}Nd| zhY&wv`;4AE;tq6xU>b`%-i_5_Obvavel595f?{CcU_tnzt2bKbCU0Nly{lft%~(q% RGnd!Cq@q>U{!Sj<_dlW*HmLvr delta 2289 zcmaKtc{~#i1IB00Y?S6muDOqi*&Jzx+(%OG`_5G?quk~ga^;v~$wVR|M~?VZQt={5 z=7{|W%aQxo+@oLb`+x8A-}m|R`}sVdXG(fXI!A~#UVj{m%Y_Q#Vp95G9yFq5Aa|IR zU7Gc2=jMACQv#v~Ek!qTVR4(Gjty+w&QooN@-Vu>laP&@9nCi&KL<5|iD}lhr2(ZY zz#4Img@6U_EgqYfn6{M$&p7{Ct_Cc<7&%(ZdmgW3N7CE=ReQh{8y$^%UM`lYAXGL( zlQoR`#t;flC*gJsIAmPO8Cva&!XNASr+LLO^~OA5MbO5GnbyTS9R9#CYcoN7*kF#I z)|O3HjxN}j%LRlKFR>MSJXv|&Z({TvaJNz2K*4#bz~O4Sl%O+rL;sFM>hF}SU!OSD zZuy^=H%0WG^|NlgrBV9zP6<05_ncOxsO}TB%hG~Z0O0^aK;U!5==&X?uvrTntT;H+ zCr+pE{7IP$%}r7smaa^o?>SDW9kC``j>()N#aw}W zPy3wI7`XNeSl8?c5=UK4GdyX}Gg1;@qwBtibxb!h+JlhiX95Cp9WXFEZ2U1Yc_byk z&Y&Ke4@uj|#(|DUk|h#`c>-En9e&gfoL$Q2I?8+DnXvQq9AwnWW!WAQwKhkoBsA3p zRcyT>yt$T(?yD<9i5S(r?fzW#E*U#-vYfAlD`yA}_3ZV?VIDKq}^f)esk2Tj(i zo;x8Ufb84;Rn%=@c*<;k8#!3KeCtfOgNhCXcV465!}xIX z->|dqli2NdKZ56F0aFy40=a#B}7q#)n;AFbX&D(I*o^Uy(-n3y!R*f~2f*Bbni<0%)Q=8taY&o>H zAy~%^?$BdaX{`PC)bz>FZUqQ}Y9Hv7IGIr_Xa+zXNj_MtGEIxtKY<|hgQk^`-DwiV z)XS{M)Zy%LFS28;%;2`CjBroCaU`#2R@cHUPyrne_H}eU8!p78iCUQ7)3< zQe|BF@Vj+#ypD2(;o}n+S|X#BYcj{vR~n@Clh~_RjS?~7!yAISeNv5j6wm@x1GvWA z6YYEQX5`kOP>d@_1F5)j(b+a_+96_^=z?WoBgS+IqS`|!bkP9k_`RM(BkLy4CmG!WV3C7iHE#u`#?l))ZS|NMH2{(wna^i;ZRXH|Tt?hcQZ*H|Qq3F!$hZJO( zor<{WcER_7^7c9#_DDiez}MoT6$2kALkF0P*wSF z{)f#Vwr407eqZkQ%^`2(A3`z*uHvC0QP(cQt~SN{Ivo9lsvWq1tOE!yA^^9_KRP70iy6d)mrSIkon&l_sD|A3y- z+i^PdN1j!%BB7YFoS|jZVE)(Snd3m1pL3?%k42EVzjL#h_Bj-IqHkLp{Y9DozLb6& z>SRcn{Vbn~quU_9CXrPPTx92(WBLwnyvE)!bW~>dxSm>5_{s}tcBD5ZIVF7CZNq7b&Z(T|@Y9&_0{+KcS1ptsFI`@L8$fF?TR{z6y;9j{61Bts_oY(;(*U zMBf|U>kSLf_WE;#@tkK2mCNTeyj%4%%am~4qjUAII}9NQcgG^xEEAK=iQnyveToBv z9!8Nilg{40$89W;M{9Y7_r!?_0{{Rf0B7he?EPEVOSine|KOj)4ki5Q```&ZaBenE z7#kA{lLC;3iHQ}!lJJUu?{p3HnwL|k^pdUoZR?eNMPuU^q7x?tDe#7Go(uV7s9b3) z$5lnZ3mXwiAY}VLU7h?dRZ4?**2~o%dhWx=GyjpG6-bv4sn1#0f4G3@2(P4sKnKQ) zdX?6o7I74x{p<5GW0gMVzGS(NJ~QW_n0Q~D{Sv}Pb8RdoUr&AdF(7OHL88G2)@#vh zQXLEHlBpcmvi0hoSNMV>FQ?n*o%??yJUExhGetByteArrayElements(jenv, certDer, NULL); + derSz = (*jenv)->GetArrayLength(jenv, certDer); + + if (der == NULL || derSz <= 0) { + ret = WOLFSSL_FAILURE; + } + + if (ret == WOLFSSL_SUCCESS) { + x509In = wolfSSL_X509_load_certificate_buffer(der, derSz, + SSL_FILETYPE_ASN1); + if (x509In == NULL) { + ret = WOLFSSL_FAILURE; + } + } + + if (ret == WOLFSSL_SUCCESS) { + /* Returns pointer into WOLFSSL_X509, no free needed on name */ + name = wolfSSL_X509_get_issuer_name(x509In); + if (name == NULL) { + ret = WOLFSSL_FAILURE; + } + } + + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_X509_set_issuer_name(x509, name); + } + + if (x509In != NULL) { + wolfSSL_X509_free(x509In); + } + + (*jenv)->ReleaseByteArrayElements(jenv, certDer, (jbyte*)der, JNI_ABORT); + + return ret; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + (void)certDer; + return (jint)NOT_COMPILED_IN; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1pubkey_1native_1open + (JNIEnv* jenv, jclass jcl, jlong x509Ptr, jint keyType, jbyteArray fileBytes, jint fileFormat) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + + byte* fileBuf = NULL; + int fileSz = 0; + byte* derBuf = NULL; + int derSz = 0; + byte derAllocated = 0; + WOLFSSL_EVP_PKEY* pub = NULL; + unsigned char* rsaPubBuf = NULL; + + int ret = WOLFSSL_SUCCESS; + (void)jcl; + + if (jenv == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + fileBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, fileBytes, NULL); + fileSz = (*jenv)->GetArrayLength(jenv, fileBytes); + + if (fileBuf == NULL || fileSz == 0) { + ret = WOLFSSL_FAILURE; + } + + /* convert PEM to DER if needed */ + if (ret == WOLFSSL_SUCCESS) { + if ((int)fileFormat == WOLFSSL_FILETYPE_ASN1) { + /* already in DER */ + derBuf = fileBuf; + derSz = fileSz; + } + else { + /* get needed buffer size */ + ret = wc_KeyPemToDer(fileBuf, fileSz, NULL, 0, NULL); + if (ret <= 0) { + ret = WOLFSSL_FAILURE; + } + else { + derSz = ret; + derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ret = WOLFSSL_SUCCESS; + derAllocated = 1; + XMEMSET(derBuf, 0, derSz); + } + } + } + } + + /* convert PEM to DER if derBuf has been allocated */ + if (derAllocated == 1 && ret == WOLFSSL_SUCCESS) { + ret = wc_KeyPemToDer(fileBuf, fileSz, derBuf, derSz, NULL); + if (ret <= 0 || ret != derSz) { + ret = WOLFSSL_FAILURE; + } + else { + ret = WOLFSSL_SUCCESS; + } + } + + /* convert buffer into WOLFSSL_EVP_PKEY */ + if (ret == WOLFSSL_SUCCESS) { + rsaPubBuf = derBuf; + + pub = wolfSSL_d2i_PUBKEY(NULL, (const unsigned char**)&rsaPubBuf, derSz); + if (pub == NULL) { + ret = WOLFSSL_FAILURE; + } + } + + /* set WOLFSSL_EVP_PKEY into WOLFSSL_X509 */ + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_X509_set_pubkey(x509, pub); + } + + if (pub != NULL) { + /* free WOLFSSL_EVP_PKEY, since X509_set_pubkey() makes copy */ + wolfSSL_EVP_PKEY_free(pub); + } + if (derAllocated == 1 && derBuf != NULL) { + XMEMSET(derBuf, 0, derSz); + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + (*jenv)->ReleaseByteArrayElements(jenv, fileBytes, (jbyte*)fileBuf, + JNI_ABORT); + + return (jint)ret; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + (void)keyType; + (void)filePath; + (void)fileFormat; + return (jint)NOT_COMPILED_IN; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1altname + (JNIEnv* jenv, jclass jcl, jlong x509Ptr, jstring altName, jint type) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA) + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + const char* name = NULL; + int ret = WOLFSSL_SUCCESS; + (void)jcl; + + if (jenv == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + name = (*jenv)->GetStringUTFChars(jenv, altName, 0); + + if (name == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ret = wolfSSL_X509_add_altname(x509, name, (int)type); + } + + (*jenv)->ReleaseStringUTFChars(jenv, altName, name); + + return (jint)ret; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + (void)altName; + (void)type; + return (jint)NOT_COMPILED_IN; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1nconf_1nid + (JNIEnv* jenv, jclass jcl, jlong x509Ptr, jint nid, jstring extValue, jboolean isCritical) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA) + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + WOLFSSL_X509_EXTENSION* ext = NULL; + const char* value = NULL; + int ret = WOLFSSL_SUCCESS; + (void)jcl; + + if (jenv == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + value = (*jenv)->GetStringUTFChars(jenv, extValue, 0); + if (value == NULL) { + ret = WOLFSSL_FAILURE; + } + + if (ret == WOLFSSL_SUCCESS) { + ext = wolfSSL_X509V3_EXT_nconf_nid(NULL, NULL, (int)nid, value); + if (ext == NULL) { + ret = WOLFSSL_FAILURE; + } + } + + if (ret == WOLFSSL_SUCCESS) { + if (isCritical == JNI_TRUE) { + ret = wolfSSL_X509_EXTENSION_set_critical(ext, 1); + } + } + + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_X509_add_ext(x509, ext, -1); + } + + if (ext != NULL) { + wolfSSL_X509_EXTENSION_free(ext); + } + + (*jenv)->ReleaseStringUTFChars(jenv, extValue, value); + + return (jint)ret; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + (void)nid; + (void)extValue; + (void)isCritical; + return (jint)NOT_COMPILED_IN; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1set_1object_1boolean + (JNIEnv* jenv, jclass jcl, jlong x509Ptr, jint nid, jboolean extValue, jboolean isCritical) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA) + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + WOLFSSL_X509_EXTENSION* ext = NULL; + WOLFSSL_ASN1_OBJECT* obj = NULL; + int ret = WOLFSSL_SUCCESS; + (void)jcl; + + if (jenv == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + ext = wolfSSL_X509_EXTENSION_new(); + if (ext == NULL) { + ret = WOLFSSL_FAILURE; + } + + if (ret == WOLFSSL_SUCCESS) { + if (isCritical == JNI_TRUE) { + ret = wolfSSL_X509_EXTENSION_set_critical(ext, 1); + } + } + + if (ret == WOLFSSL_SUCCESS) { + obj = wolfSSL_OBJ_nid2obj((int)nid); + if (obj == NULL) { + ret = WOLFSSL_FAILURE; + } + } + + if (ret == WOLFSSL_SUCCESS) { + if (extValue == JNI_TRUE) { + obj->ca = 1; + } + else { + obj->ca = 0; + } + } + + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_X509_EXTENSION_set_object(ext, obj); + } + + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_X509_add_ext(x509, ext, -1); + } + + + if (obj != NULL) { + wolfSSL_ASN1_OBJECT_free(obj); + } + if (ext != NULL) { + wolfSSL_X509_EXTENSION_free(ext); + } + + return (jint)ret; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + (void)nid; + (void)extValue; + (void)isCritical; + return (jint)NOT_COMPILED_IN; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1notBefore + (JNIEnv* jenv, jclass jcl, jlong x509Ptr, jlong notBefore) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) + + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + WOLFSSL_ASN1_TIME* asnBefore = NULL; + int ret = WOLFSSL_SUCCESS; + time_t notBeforeTime = (time_t)(long)notBefore; + (void)jcl; + + if (jenv == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + /* set time_t value into WOLFSSL_ASN1_TIME struct, no adjustment */ + asnBefore = wolfSSL_ASN1_TIME_adj(NULL, notBeforeTime, 0, 0); + if (asnBefore == NULL) { + ret = WOLFSSL_FAILURE; + } + + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_X509_set_notBefore(x509, asnBefore); + } + + if (asnBefore != NULL) { + wolfSSL_ASN1_TIME_free(asnBefore); + } + + return ret; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + (void)notBefore; + return (jint)NOT_COMPILED_IN; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1notAfter + (JNIEnv* jenv, jclass jcl, jlong x509Ptr, jlong notAfter) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) + + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + WOLFSSL_ASN1_TIME* asnAfter = NULL; + int ret = WOLFSSL_SUCCESS; + time_t notAfterTime = (time_t)(long)notAfter; + (void)jcl; + + if (jenv == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + /* set time_t value into WOLFSSL_ASN1_TIME struct, no adjustment */ + asnAfter = wolfSSL_ASN1_TIME_adj(NULL, notAfterTime, 0, 0); + if (asnAfter == NULL) { + ret = WOLFSSL_FAILURE; + } + + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_X509_set_notAfter(x509, asnAfter); + } + + if (asnAfter != NULL) { + wolfSSL_ASN1_TIME_free(asnAfter); + } + + return ret; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + (void)notAfter; + return (jint)NOT_COMPILED_IN; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1serialNumber + (JNIEnv* jenv, jclass jcl, jlong x509Ptr, jbyteArray serialBytes) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + WOLFSSL_ASN1_INTEGER* serial = NULL; + byte* serialBuf = NULL; + int serialSz = 0; + int ret = WOLFSSL_SUCCESS; + (void)jcl; + + if (jenv == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + serialBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, serialBytes, NULL); + serialSz = (*jenv)->GetArrayLength(jenv, serialBytes); + + if (serialBuf == NULL || serialSz == 0) { + ret = WOLFSSL_FAILURE; + } + + if (ret == WOLFSSL_SUCCESS) { + serial = wolfSSL_ASN1_INTEGER_new(); + if (serial == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + serial->data[0] = ASN_INTEGER; + serial->data[1] = serialSz; + XMEMCPY(&serial->data[2], serialBuf, serialSz); + serial->length = serialSz + 2; + } + } + + if (ret == WOLFSSL_SUCCESS) { + /* copies contents of ASN1_INTEGER, we can free below */ + ret = wolfSSL_X509_set_serialNumber(x509, serial); + } + + if (serial != NULL) { + wolfSSL_ASN1_INTEGER_free(serial); + } + + (*jenv)->ReleaseByteArrayElements(jenv, serialBytes, (jbyte*)serialBuf, + JNI_ABORT); + + return ret; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + (void)serialBytes; + return (jint)NOT_COMPILED_IN; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1sign + (JNIEnv* jenv, jclass jcl, jlong x509Ptr, jint keyType, jbyteArray fileBytes, jint fileFormat, jstring digestAlg) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) && \ + defined(WOLFSSL_CERT_GEN) + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + + byte* fileBuf = NULL; + int fileSz = 0; + byte* derBuf = NULL; + int derSz = 0; + byte derAllocated = 0; + WOLFSSL_EVP_PKEY* priv = NULL; + const WOLFSSL_EVP_MD* md = NULL; + unsigned char* rsaPrivBuf = NULL; + const char* mdName = NULL; + + int ret = WOLFSSL_SUCCESS; + (void)jcl; + + if (jenv == NULL || x509 == NULL) { + return WOLFSSL_FAILURE; + } + + fileBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, fileBytes, NULL); + fileSz = (*jenv)->GetArrayLength(jenv, fileBytes); + + if (fileBuf == NULL || fileSz == 0) { + ret = WOLFSSL_FAILURE; + } + + /* Set correct WOLFSSL_EVP_MD, does not need to be freed */ + if (ret == WOLFSSL_SUCCESS) { + mdName = (*jenv)->GetStringUTFChars(jenv, digestAlg, 0); + if (mdName == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + md = wolfSSL_EVP_get_digestbyname(mdName); + if (md == NULL) { + ret = WOLFSSL_FAILURE; + } + } + } + + /* convert PEM to DER if needed */ + if (ret == WOLFSSL_SUCCESS) { + if ((int)fileFormat == WOLFSSL_FILETYPE_ASN1) { + /* already in DER */ + derBuf = fileBuf; + derSz = fileSz; + } + else { + /* get needed buffer size */ + ret = wc_KeyPemToDer(fileBuf, fileSz, NULL, 0, NULL); + if (ret <= 0) { + ret = WOLFSSL_FAILURE; + } + else { + derSz = ret; + derBuf = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + ret = WOLFSSL_FAILURE; + } + else { + ret = WOLFSSL_SUCCESS; + derAllocated = 1; + XMEMSET(derBuf, 0, derSz); + } + } + } + } + + /* convert PEM to DER if derBuf has been allocated */ + if (derAllocated == 1 && ret == WOLFSSL_SUCCESS) { + ret = wc_KeyPemToDer(fileBuf, fileSz, derBuf, derSz, NULL); + if (ret <= 0 || ret != derSz) { + ret = WOLFSSL_FAILURE; + } + else { + ret = WOLFSSL_SUCCESS; + } + } + + /* convert buffer into WOLFSSL_EVP_PKEY */ + if (ret == WOLFSSL_SUCCESS) { + rsaPrivBuf = derBuf; + + priv = wolfSSL_d2i_PrivateKey((int)keyType, NULL, + (const unsigned char**)&rsaPrivBuf, derSz); + if (priv == NULL) { + ret = WOLFSSL_FAILURE; + } + } + + /* set version to v3 (only supported currently */ + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_X509_set_version(x509, 2L); + } + + /* sign WOLFSSL_X509 with WOLFSSL_EVP_PKEY, returns size of signature + * on success or negative on error */ + if (ret == WOLFSSL_SUCCESS) { + ret = wolfSSL_X509_sign(x509, priv, md); + if (ret >= 0) { + ret = WOLFSSL_SUCCESS; + } + } + + if (priv != NULL) { + wolfSSL_EVP_PKEY_free(priv); + } + if (derAllocated == 1 && derBuf != NULL) { + XMEMSET(derBuf, 0, derSz); + XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + (*jenv)->ReleaseByteArrayElements(jenv, fileBytes, (jbyte*)fileBuf, + JNI_ABORT); + (*jenv)->ReleaseStringUTFChars(jenv, digestAlg, mdName); + + return (jint)ret; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + (void)keyType; + (void)fileBytes; + (void)fileFormat; + (void)digestAlg; + return (jint)NOT_COMPILED_IN; +#endif +} + JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1load_1certificate_1buffer (JNIEnv* jenv, jclass jcl, jbyteArray in, jint format) { @@ -139,6 +805,83 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1der return derArr; } +JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1pem + (JNIEnv* jenv, jclass jcl, jlong x509Ptr) +{ +#ifdef WOLFSSL_DER_TO_PEM + int sz = 0; + const byte* der = NULL; + byte* pem = NULL; + int pemSz = 0; + jbyteArray pemArr = NULL; + jclass excClass = NULL; + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + + if (jenv == NULL || x509 == NULL) { + return NULL; + } + + der = wolfSSL_X509_get_der(x509, &sz); + if (der == NULL || sz == 0) { + return NULL; + } + + pemSz = wc_DerToPem(der, sz, NULL, 0, CERT_TYPE); + if (pemSz < 0) { + return NULL; + } + + pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (pem == NULL) { + return NULL; + } + XMEMSET(pem, 0, pemSz); + + pemSz = wc_DerToPem(der, sz, pem, pemSz, CERT_TYPE); + if (pemSz < 0) { + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + pemArr = (*jenv)->NewByteArray(jenv, pemSz); + if (pemArr == NULL) { + (*jenv)->ThrowNew(jenv, jcl, + "Failed to create byte array in native X509_get_pem"); + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionDescribe(jenv); + (*jenv)->ExceptionClear(jenv); + (*jenv)->DeleteLocalRef(jenv, pemArr); + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + (*jenv)->SetByteArrayRegion(jenv, pemArr, 0, pemSz, (jbyte*)pem); + if ((*jenv)->ExceptionOccurred(jenv)) { + (*jenv)->ExceptionDescribe(jenv); + (*jenv)->ExceptionClear(jenv); + (*jenv)->DeleteLocalRef(jenv, pemArr); + (*jenv)->ThrowNew(jenv, excClass, + "Failed to set byte region in native X509_get_pem"); + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return NULL; + } + + XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return pemArr; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + return NULL; +#endif +} + JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1tbs (JNIEnv* jenv, jclass jcl, jlong x509Ptr) { @@ -541,6 +1284,33 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1issuer_ return NULL; } +JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1issuer_1name_1ptr + (JNIEnv* jenv, jclass jcl, jlong x509Ptr) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \ + (defined(OPENSSL_EXTRA_X509_SMALL) || defined(KEEP_PEER_CERT) || \ + defined(SESSION_CERTS)) + WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr; + WOLFSSL_X509_NAME* name = NULL; + + if (jenv == NULL || x509 == NULL) { + return 0; + } + + name = wolfSSL_X509_get_issuer_name(x509); + if (name == NULL) { + return 0; + } + + return (jlong)(uintptr_t)name; +#else + (void)jenv; + (void)jcl; + (void)x509Ptr; + return (jlong)0; +#endif +} + JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1pubkey (JNIEnv* jenv, jclass jcl, jlong x509Ptr) { diff --git a/native/com_wolfssl_WolfSSLCertificate.h b/native/com_wolfssl_WolfSSLCertificate.h index ac0ffe3f..494c911d 100644 --- a/native/com_wolfssl_WolfSSLCertificate.h +++ b/native/com_wolfssl_WolfSSLCertificate.h @@ -7,6 +7,10 @@ #ifdef __cplusplus extern "C" { #endif +#undef com_wolfssl_WolfSSLCertificate_EVP_PKEY_RSA +#define com_wolfssl_WolfSSLCertificate_EVP_PKEY_RSA 16L +#undef com_wolfssl_WolfSSLCertificate_EVP_PKEY_EC +#define com_wolfssl_WolfSSLCertificate_EVP_PKEY_EC 18L /* * Class: com_wolfssl_WolfSSLCertificate * Method: X509_get_der @@ -15,6 +19,14 @@ extern "C" { JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1der (JNIEnv *, jclass, jlong); +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_get_pem + * Signature: (J)[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1pem + (JNIEnv *, jclass, jlong); + /* * Class: com_wolfssl_WolfSSLCertificate * Method: X509_get_tbs @@ -119,6 +131,14 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1subject JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1issuer_1name (JNIEnv *, jclass, jlong); +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_get_issuer_name_ptr + * Signature: (J)J + */ +JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1issuer_1name_1ptr + (JNIEnv *, jclass, jlong); + /* * Class: com_wolfssl_WolfSSLCertificate * Method: X509_get_pubkey @@ -199,6 +219,102 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1load_1certific JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1load_1certificate_1file (JNIEnv *, jclass, jstring, jint); +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_new + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1new + (JNIEnv *, jclass); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_set_subject_name + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1subject_1name + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_set_issuer_name + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1issuer_1name + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_set_issuer_name_from_der + * Signature: (J[B)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1issuer_1name_1from_1der + (JNIEnv *, jclass, jlong, jbyteArray); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_set_pubkey_native_open + * Signature: (JI[BI)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1pubkey_1native_1open + (JNIEnv *, jclass, jlong, jint, jbyteArray, jint); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_add_altname + * Signature: (JLjava/lang/String;I)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1altname + (JNIEnv *, jclass, jlong, jstring, jint); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_add_ext_via_nconf_nid + * Signature: (JILjava/lang/String;Z)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1nconf_1nid + (JNIEnv *, jclass, jlong, jint, jstring, jboolean); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_add_ext_via_set_object_boolean + * Signature: (JIZZ)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1add_1ext_1via_1set_1object_1boolean + (JNIEnv *, jclass, jlong, jint, jboolean, jboolean); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_set_notBefore + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1notBefore + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_set_notAfter + * Signature: (JJ)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1notAfter + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_set_serialNumber + * Signature: (J[B)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1set_1serialNumber + (JNIEnv *, jclass, jlong, jbyteArray); + +/* + * Class: com_wolfssl_WolfSSLCertificate + * Method: X509_sign + * Signature: (JI[BILjava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1sign + (JNIEnv *, jclass, jlong, jint, jbyteArray, jint, jstring); + #ifdef __cplusplus } #endif diff --git a/native/com_wolfssl_WolfSSLX509Name.c b/native/com_wolfssl_WolfSSLX509Name.c new file mode 100644 index 00000000..4d4906c9 --- /dev/null +++ b/native/com_wolfssl_WolfSSLX509Name.c @@ -0,0 +1,126 @@ +/* com_wolfssl_WolfSSLX509Name.c + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include + +#ifdef WOLFSSL_USER_SETTINGS + #include +#else + #include +#endif + +#include + +#include "com_wolfssl_globals.h" +#include "com_wolfssl_WolfSSLX509Name.h" + +JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLX509Name_X509_1NAME_1new + (JNIEnv* jenv, jclass jcl) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) + WOLFSSL_X509_NAME* x509Name = NULL; + (void)jcl; + + if (jenv == NULL) { + return 0; + } + + x509Name = wolfSSL_X509_NAME_new(); + if (x509Name == NULL) { + return 0; + } + + return (jlong)(uintptr_t)x509Name; +#else + (void)jenv; + (void)jcl; + return 0; +#endif +} + +JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLX509Name_X509_1NAME_1free + (JNIEnv* jenv, jclass jcl, jlong x509NamePtr) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) + WOLFSSL_X509_NAME* ptr = (WOLFSSL_X509_NAME*)(uintptr_t)x509NamePtr; + (void)jcl; + + if (jenv == NULL || ptr == NULL) { + return; + } + + wolfSSL_X509_NAME_free(ptr); +#else + (void)jenv; + (void)jcl; + (void)x509NamePtr; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLX509Name_X509_1NAME_1add_1entry_1by_1txt + (JNIEnv* jenv, jclass jcl, jlong x509NamePtr, jstring fieldStr, jint type, + jbyteArray entryArr, jint entryLen, jint loc, jint set) +{ +#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \ + (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)) + WOLFSSL_X509_NAME* ptr = (WOLFSSL_X509_NAME*)(uintptr_t)x509NamePtr; + const char* field = NULL; + unsigned char* entry = NULL; + int ret = WOLFSSL_FAILURE; + int len = 0; + (void)jcl; + (void)entryLen; + + if (jenv == NULL) { + return ret; + } + + field = (*jenv)->GetStringUTFChars(jenv, fieldStr, 0); + entry = (unsigned char*)(*jenv)->GetByteArrayElements(jenv, entryArr, NULL); + len = (*jenv)->GetArrayLength(jenv, entryArr); + + if (entry != NULL && len > 0 && field != NULL) { + + ret = wolfSSL_X509_NAME_add_entry_by_txt(ptr, field, (int)type, + entry, len, (int)loc, (int)set); + } + + (*jenv)->ReleaseByteArrayElements(jenv, entryArr, (jbyte*)entry, JNI_ABORT); + (*jenv)->ReleaseStringUTFChars(jenv, fieldStr, field); + + return (jint)ret; +#else + (void)jenv; + (void)jcl; + (void)x509NamePtr; + (void)fieldStr; + (void)type; + (void)entryArr; + (void)entryLen; + (void)loc; + (void)set; + return (jint)NOT_COMPILED_IN; +#endif +} + diff --git a/native/com_wolfssl_WolfSSLX509Name.h b/native/com_wolfssl_WolfSSLX509Name.h new file mode 100644 index 00000000..0fde184b --- /dev/null +++ b/native/com_wolfssl_WolfSSLX509Name.h @@ -0,0 +1,39 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_wolfssl_WolfSSLX509Name */ + +#ifndef _Included_com_wolfssl_WolfSSLX509Name +#define _Included_com_wolfssl_WolfSSLX509Name +#ifdef __cplusplus +extern "C" { +#endif +#undef com_wolfssl_WolfSSLX509Name_MBSTRING_UTF8 +#define com_wolfssl_WolfSSLX509Name_MBSTRING_UTF8 256L +/* + * Class: com_wolfssl_WolfSSLX509Name + * Method: X509_NAME_new + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLX509Name_X509_1NAME_1new + (JNIEnv *, jclass); + +/* + * Class: com_wolfssl_WolfSSLX509Name + * Method: X509_NAME_free + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLX509Name_X509_1NAME_1free + (JNIEnv *, jclass, jlong); + +/* + * Class: com_wolfssl_WolfSSLX509Name + * Method: X509_NAME_add_entry_by_txt + * Signature: (JLjava/lang/String;I[BIII)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLX509Name_X509_1NAME_1add_1entry_1by_1txt + (JNIEnv *, jclass, jlong, jstring, jint, jbyteArray, jint, jint, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/java/com/wolfssl/WolfSSL.java b/src/java/com/wolfssl/WolfSSL.java index 9099c41f..e3ba852f 100644 --- a/src/java/com/wolfssl/WolfSSL.java +++ b/src/java/com/wolfssl/WolfSSL.java @@ -346,6 +346,20 @@ public enum TLS_VERSION { /** Ed25519 key type */ public static final int ED25519k = 256; + /* GeneralName types. Match native values in asn.h */ + public static final int ASN_OTHER_TYPE = 0x00; + public static final int ASN_RFC822_TYPE = 0x01; + public static final int ASN_DNS_TYPE = 0x02; + public static final int ASN_DIR_TYPE = 0x04; + public static final int ASN_URI_TYPE = 0x06; + public static final int ASN_IP_TYPE = 0x07; + + /* NIDs, from native asn.h */ + public static final int NID_key_usage = 129; + public static final int NID_subject_alt_name = 131; + public static final int NID_basic_constraints = 133; + public static final int NID_ext_key_usage = 151; + /* is this object active, or has it been cleaned up? */ private boolean active = false; @@ -1048,6 +1062,15 @@ public static native int getPkcs8TraditionalOffset(byte[] in, long idx, */ public static native int getHmacMaxSize(); + /** + * Return the wolfSSL library vesrion number in hex. + * + * Wrapper around native wolfSSL_lib_version_hex() + * + * @return wolfSSL native library version hex value + */ + public static native long getLibVersionHex(); + /** * Returns the enabled cipher suites for native wolfSSL. * diff --git a/src/java/com/wolfssl/WolfSSLCertificate.java b/src/java/com/wolfssl/WolfSSLCertificate.java index fa9efab7..e0aab090 100644 --- a/src/java/com/wolfssl/WolfSSLCertificate.java +++ b/src/java/com/wolfssl/WolfSSLCertificate.java @@ -23,7 +23,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.ByteArrayInputStream; +import java.io.File; import java.nio.charset.Charset; +import java.nio.file.Files; import java.math.BigInteger; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -33,9 +35,16 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.security.PublicKey; +import java.security.PrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.ECPrivateKey; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; +import java.security.cert.CertificateEncodingException; /** * WolfSSLCertificate class, wraps native wolfSSL WOLFSSL_X509 functionality. @@ -52,10 +61,19 @@ public class WolfSSLCertificate { /* lock around active state */ private final Object stateLock = new Object(); + /* lock around native WOLFSSL_X509 pointer use */ + private final Object x509Lock = new Object(); + /* cache alt names once retrieved once */ private Collection> altNames = null; + /* Public key types used for certificate generation, mirrored from + * native enum in wolfssl/openssl/evp.h */ + private static final int EVP_PKEY_RSA = 16; + private static final int EVP_PKEY_EC = 18; + static native byte[] X509_get_der(long x509); + static native byte[] X509_get_pem(long x509); static native byte[] X509_get_tbs(long x509); static native void X509_free(long x509); static native int X509_get_serial_number(long x509, byte[] out); @@ -69,6 +87,7 @@ public class WolfSSLCertificate { static native int X509_get_isCA(long x509); static native String X509_get_subject_name(long x509); static native String X509_get_issuer_name(long x509); + static native long X509_get_issuer_name_ptr(long x509); static native byte[] X509_get_pubkey(long x509); static native String X509_get_pubkey_type(long x509); static native int X509_get_pathLength(long x509); @@ -80,6 +99,45 @@ public class WolfSSLCertificate { static native long X509_load_certificate_buffer(byte[] buf, int format); static native long X509_load_certificate_file(String path, int format); + /* native functions used for X509v3 certificate generation */ + static native long X509_new(); + static native int X509_set_subject_name(long x509Ptr, long x509NamePtr); + static native int X509_set_issuer_name(long x509Ptr, long x509NamePtr); + static native int X509_set_issuer_name_from_der(long x509Ptr, byte[] certDer); + static native int X509_set_pubkey_native_open(long x509Ptr, int keyType, + byte[] fileBytes, int format); + static native int X509_add_altname(long x509Ptr, String name, int type); + static native int X509_add_ext_via_nconf_nid(long x509Ptr, int nid, + String extValue, boolean isCritical); + static native int X509_add_ext_via_set_object_boolean(long x509Ptr, + int nid, boolean extValue, boolean isCritical); + static native int X509_set_notBefore(long x509Ptr, long timeSecs); + static native int X509_set_notAfter(long x509Ptr, long timeSecs); + static native int X509_set_serialNumber(long x509Ptr, byte[] serialBytes); + static native int X509_sign(long x509Ptr, int evpKeyType, byte[] keyBytes, + int format, String digestAlg); + + /** + * Create new empty WolfSSLCertificate object, for use with X509v3 + * certificate generation. + * + * @throws WolfSSLException if native API call fails. + */ + public WolfSSLCertificate() throws WolfSSLException { + + x509Ptr = X509_new(); + if (x509Ptr == 0) { + throw new WolfSSLException("Failed to create WolfSSLCertificate"); + } + + /* x509Ptr has been allocated natively, mark as owned */ + this.weOwnX509Ptr = true; + + synchronized (stateLock) { + this.active = true; + } + } + /** * Create new WolfSSLCertificate from DER-encoded byte array. * @@ -237,59 +295,760 @@ public WolfSSLCertificate(long x509) throws WolfSSLException { } /** - * Get ASN.1/DER encoding of this X.509 certificate + * Verifies that the current WolfSSLCertificate object is active. * - * @return DER encoded array of certificate or null if not available. + * @throws IllegalStateException if object has been freed */ - public byte[] getDer() { + private void confirmObjectIsActive() + throws IllegalStateException { synchronized (stateLock) { - if (this.active == true) { - return X509_get_der(this.x509Ptr); + if (this.active == false) { + throw new IllegalStateException( + "WolfSSLCertificate object has been freed"); } } + } - return null; + /** + * Protected method to be used by objects of this class to get + * internal WOLFSSL_X509 pointer. + * + * @return internal WOLFSSL_X509 pointer value + * @throws IllegalStateException if object has been freed + */ + protected long getX509Ptr() throws IllegalStateException { + + confirmObjectIsActive(); + + return this.x509Ptr; } /** - * Get buffer that is To Be Signed (Tbs) + * Set the Subject Name to be used with this WolfSSLCertificate. + * Note that the WolfSSLX509Name object should be completely set up + * before calling this method. This method copies/duplicates the contents + * of the WOLFSSL_X509_NAME (WolfSSLX509Name) into the native + * WOLFSSL_X509 structure. * - * @return byte array to be signed + * @param name Initialized and populated WolfSSLX509 name to be set into + * Subject Name of WolfSSLCertificate for cert generation. + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if native JNI error occurs. */ - public byte[] getTbs() { + public void setSubjectName(WolfSSLX509Name name) + throws IllegalStateException, WolfSSLException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_tbs(this.x509Ptr); + int ret; + + confirmObjectIsActive(); + + synchronized (x509Lock) { + /* TODO somehow lock WolfSSLX509Name object while using pointer? */ + ret = X509_set_subject_name(this.x509Ptr, + name.getNativeX509NamePtr()); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException("Error setting subject name " + + "(ret: " + ret + ")"); + } + } + + /** + * Set the Issuer Name to be used with this WolfSSLCertificate. + * Note that the WolfSSLX509Name object should be completely set up + * before calling this method. This method copies/duplicates the contents + * of the WOLFSSL_X509_NAME (WolfSSLX509Name) into the native + * WOLFSSL_X509 structure. + * + * @param name Initialized and populated WolfSSLX509 name to be set into + * Issuer Name of WolfSSLCertificate for cert generation. + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if native JNI error occurs. + */ + public void setIssuerName(WolfSSLX509Name name) + throws IllegalStateException, WolfSSLException { + + int ret; + + confirmObjectIsActive(); + + synchronized (x509Lock) { + /* TODO somehow lock WolfSSLX509Name object while using pointer? */ + ret = X509_set_issuer_name(this.x509Ptr, + name.getNativeX509NamePtr()); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException("Error setting issuer name " + + "(ret: " + ret + ")"); + } + } + + /** + * Set the Issuer Name to be used with this WolfSSLCertificate. + * This method copies the issuer name from the existing populated + * WolfSSLCertificate object, which would commonly be initialized + * from a CA certificate file or byte array. + * + * @param cert Initialized and populated WolfSSLCertificate to be set into + * Issuer Name of this WolfSSLCertificate for cert generation. + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if native JNI error occurs. + */ + public void setIssuerName(WolfSSLCertificate cert) + throws IllegalStateException, WolfSSLException { + + int ret; + long x509CertPtr = 0; + long x509NamePtr = 0; + + confirmObjectIsActive(); + + x509NamePtr = X509_get_issuer_name_ptr(cert.getX509Ptr()); + if (x509NamePtr == 0) { + throw new WolfSSLException("Error getting issuer name from " + + "WolfSSLCertificate"); + } + + synchronized (x509Lock) { + /* TODO somehow lock WolfSSLX509Name object while using pointer? */ + ret = X509_set_issuer_name(this.x509Ptr, x509NamePtr); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException("Error setting issuer name " + + "(ret: " + ret + ")"); + } + } + + /** + * Set the Issuer Name to be used with this WolfSSLCertificate. + * This method copies the issuer name from the existing populated + * X509Certificate object. + * + * @param cert Initialized and populated X509Certificate to be used to set + * Issuer Name of this WolfSSLCertificate for cert generation. + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if native JNI error occurs. + * @throws CertificateEncodingException if error occurs while parsing + * X509Certificate + */ + public void setIssuerName(X509Certificate cert) + throws IllegalStateException, WolfSSLException, + CertificateEncodingException { + + int ret; + byte[] certDer = null; + + confirmObjectIsActive(); + + /* Get DER encoding of certificate */ + certDer = cert.getEncoded(); + + synchronized (x509Lock) { + ret = X509_set_issuer_name_from_der(this.x509Ptr, certDer); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException("Error setting issuer name " + + "(ret: " + ret + ")"); + } + } + + /** + * Set public key for this WolfSSLCertificate, used when generating + * X509v3 certificates. + * + * @param filePath Path to public key file + * @param keyType Type of public key algorithm, options are: + * WolfSSL.RSAk + * WolfSSL.ECDSAk + * @param format Format of public key file, options are: + * WolfSSL.SSL_FILETYPE_ASN1 (DER formatted) + * WolfSSL.SSL_FILETYPE_PEM (PEM formatted) + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws IOException on error opening input file + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void setPublicKey(String filePath, int keyType, int format) + throws IllegalStateException, IOException, WolfSSLException { + + int ret = 0; + File keyFile = null; + + confirmObjectIsActive(); + + if (filePath == null || filePath.isEmpty()) { + throw new WolfSSLException("File path is null or empty"); + } + + keyFile = new File(filePath); + if (!keyFile.exists()) { + throw new WolfSSLException("Input file does not exist: " + + filePath); + } + + setPublicKey(Files.readAllBytes(keyFile.toPath()), keyType, format); + } + + /** + * Set public key for this WolfSSLCertificate, used when generating + * X509v3 certificates. + * + * @param key Byte array containing public key + * @param keyType Type of public key algorithm, options are: + * WolfSSL.RSAk + * WolfSSL.ECDSAk + * @param format Format of public key file, options are: + * WolfSSL.SSL_FILETYPE_ASN1 (DER formatted) + * WolfSSL.SSL_FILETYPE_PEM (PEM formatted) + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws IOException on error opening input file + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void setPublicKey(byte[] key, int keyType, int format) + throws IllegalStateException, IOException, WolfSSLException { + + int ret = 0; + int evpKeyType; + + confirmObjectIsActive(); + + if (key == null || key.length == 0) { + throw new WolfSSLException("Key array is null or empty"); + } + + if (format != WolfSSL.SSL_FILETYPE_ASN1 && + format != WolfSSL.SSL_FILETYPE_PEM) { + throw new WolfSSLException( + "Invalid key format, must be PEM or DER"); + } + + switch (keyType) { + case WolfSSL.RSAk: + evpKeyType = EVP_PKEY_RSA; + break; + case WolfSSL.ECDSAk: + evpKeyType = EVP_PKEY_EC; + break; + default: + throw new WolfSSLException("Unsupported public key type"); + } + + synchronized (x509Lock) { + ret = X509_set_pubkey_native_open(this.x509Ptr, evpKeyType, + key, format); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException( + "Error setting public key into native WOLFSSL_X509 " + + "(ret: " + ret + ")"); + } + } + + /** + * Set public key for this WolfSSLCertificate, used when generating + * X509v3 certificates. + * + * @param key PublicKey object containing public key to be used when + * generating X509v3 certificate. + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + * @throws IOException on error opening/reading public key + */ + public void setPublicKey(PublicKey key) + throws IllegalStateException, IOException, WolfSSLException { + + int keyType; + byte[] encodedKey = null; + + confirmObjectIsActive(); + + if (key instanceof RSAPublicKey) { + keyType = WolfSSL.RSAk; + } + else if (key instanceof ECPublicKey) { + keyType = WolfSSL.ECDSAk; + } + else { + throw new WolfSSLException( + "PublicKey must be of type RSAPublicKey or ECPublicKey"); + } + + /* Get DER encoded key */ + encodedKey = key.getEncoded(); + if (encodedKey == null) { + throw new WolfSSLException( + "Error getting encoded (DER) format of PublicKey"); + } + + setPublicKey(encodedKey, keyType, WolfSSL.SSL_FILETYPE_ASN1); + } + + /** + * Sets the serial number for this WolfSSLCertificate, used when + * generating X509v3 certificates. + * + * @param serial BigInteger holding serial number for generated cert + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void setSerialNumber(BigInteger serial) + throws IllegalStateException, WolfSSLException { + + int ret = 0; + byte[] serialBytes = null; + + confirmObjectIsActive(); + + if (serial == null) { + throw new WolfSSLException("Input BigInteger is null"); + } + + serialBytes = serial.toByteArray(); + if (serialBytes == null || serialBytes.length == 0) { + throw new WolfSSLException("BigInteger.toByteArray() " + + "is null or 0 length"); + } + + synchronized (x509Lock) { + ret = X509_set_serialNumber(this.x509Ptr, serialBytes); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException( + "Error setting serial number into native WOLFSSL_X509 " + + "(ret: " + ret + ")"); + } + } + + /** + * Sets the notBefore date for this WolfSSLCertificate, used when + * generating X509v3 certificates. + * + * @param notBefore Date object representing notBefore date/time to set + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void setNotBefore(Date notBefore) + throws IllegalStateException, WolfSSLException { + + int ret = 0; + + confirmObjectIsActive(); + + synchronized (x509Lock) { + ret = X509_set_notBefore(this.x509Ptr, notBefore.getTime() / 1000); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException( + "Error setting notBefore date into native WOLFSSL_X509 " + + "(ret: " + ret + ")"); + } + } + + /** + * Sets the notAfter date for this WolfSSLCertificate, used when + * generating X509v3 certificates. + * + * @param notAfter Date object representing notAfter date/time to set + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void setNotAfter(Date notAfter) + throws IllegalStateException, WolfSSLException { + + int ret = 0; + + confirmObjectIsActive(); + + synchronized (x509Lock) { + ret = X509_set_notAfter(this.x509Ptr, notAfter.getTime() / 1000); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException( + "Error setting notAfter date into native WOLFSSL_X509 " + + "(ret: " + ret + ")"); + } + } + + /** + * Add subject alternative name for this WolfSSLCertificate, used when + * generating X509v3 certificates. + * + * @param name String value of subject alternative name to set + * @param type Type of subject alt name entry, must be one of: + * WolfSSL.ASN_OTHER_TYPE, WolfSSL.ASN_RFC822_TYPE, + * WolfSSL.ASN_DNS_TYPE, WolfSSL.ASN_DIR_TYPE, WolfSSL.ASN_URI_TYPE, + * WolfSSL.ASN_IP_TYPE + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void addAltName(String name, int type) + throws IllegalStateException, WolfSSLException { + + int ret = 0; + + confirmObjectIsActive(); + + synchronized (x509Lock) { + ret = X509_add_altname(this.x509Ptr, name, type); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException( + "Error setting altName into native WOLFSSL_X509 " + + "(ret: " + ret + ")"); + } + } + + /** + * Add an extension to a WOLFSSL_X509 given the NID and extension + * value String. + * + * This method supports the following extensions: + * - Key Usage (WolfSSL.NID_key_usage) + * - Extended Key Usage (WolfSSL.NID_ext_key_usage) + * - Subject Alt Name (WolfSSL.NED_subject_alt_name) + * + * @param nid NID of extension to add. Must be one of: + * WolfSSL.NID_key_usage + * WolfSSL.NID_subject_alt_name + * @param value String value of extension to set + * @param isCritical Boolean flag indicating if this extension is + * critical + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void addExtension(int nid, String value, boolean isCritical) + throws IllegalStateException, WolfSSLException { + + int ret = 0; + + confirmObjectIsActive(); + + if (nid != WolfSSL.NID_key_usage && + nid != WolfSSL.NID_subject_alt_name && + nid != WolfSSL.NID_ext_key_usage) { + throw new WolfSSLException( + "Unsupported X509v3 extension NID: " + nid); + } + + synchronized (x509Lock) { + ret = X509_add_ext_via_nconf_nid(this.x509Ptr, nid, value, + isCritical); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + if ((WolfSSL.getLibVersionHex() <= 0x05006003) && + (nid == WolfSSL.NID_key_usage || + nid == WolfSSL.NID_ext_key_usage)) { + + /* wolfSSL versions 5.6.3 and earlier did not include code + * fixes to native wolfSSL allowing this extension support to + * work. Use a version > 5.6.3 or apply patch from wolfSSL + * PR 6585 for correct support */ + throw new WolfSSLException( + "Error setting extension into native WOLFSSL_X509 " + + "(ret: " + ret + ").\nNeed to use wolfSSL version " + + "greater than 5.6.3 for extension support (PR 6585)."); } + + throw new WolfSSLException( + "Error setting extension into native WOLFSSL_X509 " + + "(ret: " + ret + ")"); } + } - return null; + /** + * Add an extension to a WOLFSSL_X509 given the NID and extension + * value true/false value. + * + * This method supports the following extensions: + * - Basic Constraints (WolfSSL.NID_basic_constraints) + * + * @param nid NID of extension to add. Must be one of: + * WolfSSL.NID_key_usage + * WolfSSL.NID_subject_alt_name + * @param value Boolean value of extension (true/false) + * @param isCritical Boolean flag indicating if this extension is + * critical + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void addExtension(int nid, boolean value, boolean isCritical) + throws IllegalStateException, WolfSSLException { + + int ret = 0; + + confirmObjectIsActive(); + + if (nid != WolfSSL.NID_basic_constraints) { + throw new WolfSSLException( + "Unsupported X509v3 extension NID: " + nid); + } + + synchronized (x509Lock) { + ret = X509_add_ext_via_set_object_boolean( + this.x509Ptr, nid, value, isCritical); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException( + "Error setting extension into native WOLFSSL_X509 " + + "(ret: " + ret + ")"); + } + } + + /** + * Sign certificate with private key from file. + * + * @param filePath Path to private key file + * @param keyType Type of public key algorithm, options are: + * WolfSSL.RSAk + * WolfSSL.ECDSAk + * @param format Format of private key file, options are: + * WolfSSL.SSL_FILETYPE_ASN1 (DER formatted) + * WolfSSL.SSL_FILETYPE_PEM (PEM formatted) + * @param digestAlg Message digest algorithm to use for signature + * generation. Options include the following, but native algorithm + * must be compiled into wolfSSL to be available: + * "MD4", "MD5", "SHA1", "SHA224", "SHA256", "SHA384", + * "SHA512", "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512" + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws IOException on error opening input file + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void signCert(String filePath, int keyType, int format, + String digestAlg) throws IllegalStateException, IOException, + WolfSSLException { + + int ret = 0; + File keyFile = null; + + confirmObjectIsActive(); + + if (filePath == null || filePath.isEmpty()) { + throw new WolfSSLException("File path is null or empty"); + } + + keyFile = new File(filePath); + if (!keyFile.exists()) { + throw new WolfSSLException("Input file does not exist: " + + filePath); + } + + signCert(Files.readAllBytes(keyFile.toPath()), keyType, format, + digestAlg); + } + + /** + * Sign certificate with private key from buffer. + * + * @param key Byte array containing private key + * @param keyType Type of public key algorithm, options are: + * WolfSSL.RSAk + * WolfSSL.ECDSAk + * @param format Format of private key file, options are: + * WolfSSL.SSL_FILETYPE_ASN1 (DER formatted) + * WolfSSL.SSL_FILETYPE_PEM (PEM formatted) + * @param digestAlg Message digest algorithm to use for signature + * generation. Options include the following, but native algorithm + * must be compiled into wolfSSL to be available: + * "MD4", "MD5", "SHA1", "SHA224", "SHA256", "SHA384", + * "SHA512", "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512" + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void signCert(byte[] key, int keyType, int format, + String digestAlg) throws IllegalStateException, WolfSSLException { + + int ret = 0; + int evpKeyType; + + confirmObjectIsActive(); + + if (key == null || key.length == 0) { + throw new WolfSSLException("Key array is null or empty"); + } + + if (format != WolfSSL.SSL_FILETYPE_ASN1 && + format != WolfSSL.SSL_FILETYPE_PEM) { + throw new WolfSSLException( + "Invalid key format, must be PEM or DER"); + } + + switch (keyType) { + case WolfSSL.RSAk: + evpKeyType = EVP_PKEY_RSA; + break; + case WolfSSL.ECDSAk: + evpKeyType = EVP_PKEY_EC; + break; + default: + throw new WolfSSLException("Unsupported private key type"); + } + + synchronized (x509Lock) { + ret = X509_sign(this.x509Ptr, evpKeyType, key, format, digestAlg); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException( + "Error signing native WOLFSSL_X509 " + + "(ret: " + ret + ")"); + } + } + + /** + * Sign certificate with private key from PrivateKey object. + * + * @param key java.security.PrivateKey object containing private key, + * must be of type RSAPrivateKey or ECPrivateKey + * @param digestAlg Message digest algorithm to use for signature + * generation. Options include the following, but native algorithm + * must be compiled into wolfSSL to be available: + * "MD4", "MD5", "SHA1", "SHA224", "SHA256", "SHA384", + * "SHA512", "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512" + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLException if invalid arguments or native JNI error occurs. + */ + public void signCert(PrivateKey key, String digestAlg) + throws IllegalStateException, WolfSSLException { + + int ret = 0; + int evpKeyType; + byte[] encodedKey = null; + + confirmObjectIsActive(); + + if (key == null) { + throw new WolfSSLException("Key object is null"); + } + + if (key instanceof RSAPrivateKey) { + evpKeyType = EVP_PKEY_RSA; + } + else if (key instanceof ECPrivateKey) { + evpKeyType = EVP_PKEY_EC; + } + else { + throw new WolfSSLException( + "PrivateKey must be of type RSAPrivateKey or ECPrivateKey"); + } + + /* Get DER encoded key */ + encodedKey = key.getEncoded(); + if (encodedKey == null) { + throw new WolfSSLException("PrivateKey does not support encoding"); + } + + synchronized (x509Lock) { + ret = X509_sign(this.x509Ptr, evpKeyType, encodedKey, + WolfSSL.SSL_FILETYPE_ASN1, digestAlg); + } + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException( + "Error signing native WOLFSSL_X509 " + + "(ret: " + ret + ")"); + } + } + + /** + * Get ASN.1/DER encoding of this X.509 certificate + * + * @return DER encoded array of certificate or null if not available. + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLJNIException if native JNI operation fails + */ + public byte[] getDer() throws IllegalStateException, WolfSSLJNIException { + + confirmObjectIsActive(); + + synchronized (x509Lock) { + return X509_get_der(this.x509Ptr); + } + } + + /** + * Get PEM encoding of this X.509 certificate + * + * @return PEM encoded array of certificate or null if not available. + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + * @throws WolfSSLJNIException if native JNI operation fails + */ + public byte[] getPem() throws IllegalStateException, WolfSSLJNIException { + + confirmObjectIsActive(); + + synchronized (x509Lock) { + return X509_get_pem(this.x509Ptr); + } + } + + /** + * Get buffer that is To Be Signed (Tbs) + * + * @return byte array to be signed + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. + */ + public byte[] getTbs() throws IllegalStateException { + + confirmObjectIsActive(); + + synchronized (x509Lock) { + return X509_get_tbs(this.x509Ptr); + } } /** * Get X.509 serial number as BigInteger * * @return serial number as BigInteger, or null if not available + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public BigInteger getSerial() { + public BigInteger getSerial() throws IllegalStateException { + byte[] out = new byte[32]; int sz; - synchronized (stateLock) { - if (this.active == false) { - return null; - } + confirmObjectIsActive(); - sz = X509_get_serial_number(this.x509Ptr, out); - if (sz <= 0) { - return null; - } - else { - byte[] serial = Arrays.copyOf(out, sz); - return new BigInteger(serial); - } + synchronized (x509Lock) { + sz = X509_get_serial_number(this.x509Ptr, out); + } + if (sz <= 0) { + return null; + } + else { + byte[] serial = Arrays.copyOf(out, sz); + return new BigInteger(serial); } } @@ -297,26 +1056,28 @@ public BigInteger getSerial() { * Get X.509 validity notBefore date * * @return notBefore date as Date object, or null if not available + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public Date notBefore() { + public Date notBefore() throws IllegalStateException { + String nb; - synchronized (stateLock) { - if (this.active == false) { - return null; - } + confirmObjectIsActive(); + synchronized (x509Lock) { nb = X509_notBefore(this.x509Ptr); - if (nb != null) { - SimpleDateFormat format = - new SimpleDateFormat("MMM dd HH:mm:ss yyyy zzz"); - try { - return format.parse(nb); - } catch (ParseException ex) { - /* error case parsing date */ - } + } + if (nb != null) { + SimpleDateFormat format = + new SimpleDateFormat("MMM dd HH:mm:ss yyyy zzz"); + try { + return format.parse(nb); + } catch (ParseException ex) { + /* error case parsing date */ } } + return null; } @@ -324,26 +1085,28 @@ public Date notBefore() { * Get X.509 validity notAfter date * * @return notAfter date as Date object, or null if not available + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public Date notAfter() { + public Date notAfter() throws IllegalStateException { + String nb; - synchronized (stateLock) { - if (this.active == false) { - return null; - } + confirmObjectIsActive(); + synchronized (x509Lock) { nb = X509_notAfter(this.x509Ptr); - if (nb != null) { - SimpleDateFormat format = - new SimpleDateFormat("MMM dd HH:mm:ss yyyy zzz"); - try { - return format.parse(nb); - } catch (ParseException ex) { - /* error case parsing date */ - } + } + if (nb != null) { + SimpleDateFormat format = + new SimpleDateFormat("MMM dd HH:mm:ss yyyy zzz"); + try { + return format.parse(nb); + } catch (ParseException ex) { + /* error case parsing date */ } } + return null; } @@ -351,160 +1114,160 @@ public Date notAfter() { * Get X.509 version * * @return version of X.509 certificate + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public int getVersion() { + public int getVersion() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_version(this.x509Ptr); - } - } + confirmObjectIsActive(); - return 0; + synchronized (x509Lock) { + return X509_version(this.x509Ptr); + } } /** * Get signature from X.509 certificate * * @return byte array with signature from X.509 certificate, or null + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public byte[] getSignature() { + public byte[] getSignature() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_signature(this.x509Ptr); - } - } + confirmObjectIsActive(); - return null; + synchronized (x509Lock) { + return X509_get_signature(this.x509Ptr); + } } /** * Get signature type from X.509 certificate * * @return signature type String, or null + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public String getSignatureType() { + public String getSignatureType() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_signature_type(this.x509Ptr); - } - } + confirmObjectIsActive(); - return null; + synchronized (x509Lock) { + return X509_get_signature_type(this.x509Ptr); + } } /** * Get X.509 signature algorithm OID * * @return algorithm OID of signature, or null + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public String getSignatureOID() { + public String getSignatureOID() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_signature_OID(this.x509Ptr); - } - } + confirmObjectIsActive(); - return null; + synchronized (x509Lock) { + return X509_get_signature_OID(this.x509Ptr); + } } /** * Get public key from X.509 certificate * * @return certificate public key, byte array. Or null. + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public byte[] getPubkey() { + public byte[] getPubkey() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_pubkey(this.x509Ptr); - } - } + confirmObjectIsActive(); - return null; + synchronized (x509Lock) { + return X509_get_pubkey(this.x509Ptr); + } } /** * Get public key type of certificate * * @return public key type String, or null + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public String getPubkeyType() { + public String getPubkeyType() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_pubkey_type(this.x509Ptr); - } - } + confirmObjectIsActive(); - return null; + synchronized (x509Lock) { + return X509_get_pubkey_type(this.x509Ptr); + } } /** * Get certificate isCA value * * @return X.509 isCA value + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public int isCA() { + public int isCA() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_isCA(this.x509Ptr); - } - } + confirmObjectIsActive(); - return 0; + synchronized (x509Lock) { + return X509_get_isCA(this.x509Ptr); + } } /** * Get certificate path length * * @return path length, or -1 if not set + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public int getPathLen() { + public int getPathLen() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_pathLength(this.x509Ptr); - } - } + confirmObjectIsActive(); - return 0; + synchronized (x509Lock) { + return X509_get_pathLength(this.x509Ptr); + } } /** * Get certificate Subject * * @return X.509 Subject String, or null + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public String getSubject() { + public String getSubject() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_subject_name(this.x509Ptr); - } - } + confirmObjectIsActive(); - return null; + synchronized (x509Lock) { + return X509_get_subject_name(this.x509Ptr); + } } /** * Get certificate Issuer * * @return X.509 Issuer String, or null + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public String getIssuer() { + public String getIssuer() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_issuer_name(this.x509Ptr); - } - } + confirmObjectIsActive(); - return null; + synchronized (x509Lock) { + return X509_get_issuer_name(this.x509Ptr); + } } /** @@ -514,19 +1277,21 @@ public String getIssuer() { * @param pubKeySz size of public key array, bytes * * @return true if verified, otherwise false + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public boolean verify(byte[] pubKey, int pubKeySz) { + public boolean verify(byte[] pubKey, int pubKeySz) + throws IllegalStateException { + int ret; - synchronized (stateLock) { - if (this.active == false) { - return false; - } + confirmObjectIsActive(); + synchronized (x509Lock) { ret = X509_verify(this.x509Ptr, pubKey, pubKeySz); - if (ret == WolfSSL.SSL_SUCCESS) { - return true; - } + } + if (ret == WolfSSL.SSL_SUCCESS) { + return true; } return false; @@ -547,16 +1312,16 @@ public boolean verify(byte[] pubKey, int pubKeySz) { * [8] = KEYUSE_DECIPHER_ONLY * * @return arrray of key usages set for certificate, or null + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public boolean[] getKeyUsage() { + public boolean[] getKeyUsage() throws IllegalStateException { - synchronized (stateLock) { - if (this.active == true) { - return X509_get_key_usage(this.x509Ptr); - } - } + confirmObjectIsActive(); - return null; + synchronized (x509Lock) { + return X509_get_key_usage(this.x509Ptr); + } } /** @@ -565,13 +1330,18 @@ public boolean[] getKeyUsage() { * @param oid OID value of extension to retreive value for * * @return DER encoded extension value, or null + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public byte[] getExtension(String oid) { + public byte[] getExtension(String oid) throws IllegalStateException { - synchronized (stateLock) { - if (oid == null || this.active == false) { - return null; - } + confirmObjectIsActive(); + + if (oid == null) { + return null; + } + + synchronized (x509Lock) { return X509_get_extension(this.x509Ptr, oid); } } @@ -585,13 +1355,14 @@ public byte[] getExtension(String oid) { * 2 if extension OID is set and is critical, * 0 if not set, * otherwise negative value on error + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public int getExtensionSet(String oid) { + public int getExtensionSet(String oid) throws IllegalStateException { - synchronized (stateLock) { - if (this.active == false) { - return 0; - } + confirmObjectIsActive(); + + synchronized (x509Lock) { return X509_is_extension_set(this.x509Ptr, oid); } } @@ -608,21 +1379,22 @@ public int getExtensionSet(String oid) { * second list element being a String. * * @return immutable Collection of subject alternative names, or null + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. */ - public Collection> getSubjectAltNames() { + public Collection> getSubjectAltNames() + throws IllegalStateException { - synchronized (stateLock) { - if (this.active == false) { - throw new IllegalStateException("Object has been freed"); - } + confirmObjectIsActive(); - if (this.altNames != null) { - /* already gathered, return cached version */ - return this.altNames; - } + if (this.altNames != null) { + /* already gathered, return cached version */ + return this.altNames; + } - Collection> names = new ArrayList>(); + Collection> names = new ArrayList>(); + synchronized (x509Lock) { String nextAltName = X509_get_next_altname(this.x509Ptr); while (nextAltName != null) { Object[] entry = new Object[2]; @@ -633,44 +1405,43 @@ public Collection> getSubjectAltNames() { names.add(Collections.unmodifiableList(entryList)); nextAltName = X509_get_next_altname(this.x509Ptr); } + } - /* cache altNames collection for later use */ - this.altNames = Collections.unmodifiableCollection(names); + /* cache altNames collection for later use */ + this.altNames = Collections.unmodifiableCollection(names); - return this.altNames; - } + return this.altNames; } /** * Returns X509Certificate object based on this certificate. * * @return X509Certificate object + * + * @throws IllegalStateException if WolfSSLCertificate has been freed. * @throws CertificateException on error * @throws IOException on error closing ByteArrayInputStream + * @throws WolfSSLJNIException if native JNI error occurs */ public X509Certificate getX509Certificate() - throws CertificateException, IOException { + throws IllegalStateException, CertificateException, IOException, + WolfSSLJNIException { X509Certificate cert = null; InputStream in = null; - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - synchronized (stateLock) { - if (this.active == false) { - throw new CertificateException("Object has been freed"); - } + confirmObjectIsActive(); - try { - in = new ByteArrayInputStream(this.getDer()); - cert = (X509Certificate)cf.generateCertificate(in); - in.close(); + try { + in = new ByteArrayInputStream(this.getDer()); + cert = (X509Certificate)cf.generateCertificate(in); + in.close(); - } catch (Exception e) { - if (in != null) { - in.close(); - throw e; - } + } catch (Exception e) { + if (in != null) { + in.close(); + throw e; } } @@ -687,7 +1458,9 @@ public String toString() { return super.toString(); } - x509Text = X509_print(this.x509Ptr); + synchronized (x509Lock) { + x509Text = X509_print(this.x509Ptr); + } if (x509Text != null) { /* let Java do the modified UTF-8 conversion */ return new String(x509Text, Charset.forName("UTF-8")); @@ -698,11 +1471,9 @@ public String toString() { } /** - * Frees an X509. - * - * @throws IllegalStateException WolfSSLCertificate has been freed + * Frees WolfSSLCertificate native resources. */ - public synchronized void free() throws IllegalStateException { + public synchronized void free() { synchronized (stateLock) { if (this.active == false) { @@ -713,15 +1484,17 @@ public synchronized void free() throws IllegalStateException { /* set this.altNames to null so GC can free */ this.altNames = null; - /* only free native resources if we own pointer */ - if (this.weOwnX509Ptr == true) { - /* free native resources */ - X509_free(this.x509Ptr); - } + synchronized (x509Lock) { + /* only free native resources if we own pointer */ + if (this.weOwnX509Ptr == true) { + /* free native resources */ + X509_free(this.x509Ptr); + } - /* free Java resources */ - this.active = false; - this.x509Ptr = 0; + /* free Java resources */ + this.active = false; + this.x509Ptr = 0; + } } } @@ -733,3 +1506,4 @@ protected void finalize() throws Throwable super.finalize(); } } + diff --git a/src/java/com/wolfssl/WolfSSLX509Name.java b/src/java/com/wolfssl/WolfSSLX509Name.java new file mode 100644 index 00000000..316add3a --- /dev/null +++ b/src/java/com/wolfssl/WolfSSLX509Name.java @@ -0,0 +1,527 @@ +/* WolfSSLX509Name.java + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +package com.wolfssl; + +/** + * WolfSSLX509Name class, wraps native WOLFSSL_X509_NAME functionality. + */ +public class WolfSSLX509Name { + + private boolean active = false; + private long x509NamePtr = 0; + + /* Lock around active state */ + private final Object stateLock = new Object(); + + /* Cache name elements in Java before pushing through JNI, for easier + * retrieval from getXXX() methods */ + private String countryName = null; + private String stateOrProvinceName = null; + private String streetAddress = null; + private String localityName = null; + private String surname = null; + private String commonName = null; + private String emailAddress = null; + private String organizationName = null; + private String organizationalUnitName = null; + private String postalCode = null; + private String userId = null; + + /* Encoding types, matched to native define values */ + private static final int MBSTRING_UTF8 = 0x100; + + /* Native JNI methods */ + static native long X509_NAME_new(); + static native void X509_NAME_free(long x509Name); + static native int X509_NAME_add_entry_by_txt(long x509Name, String field, + int type, byte[] entry, int len, int loc, int set); + + /** + * Create new empty WolfSSLX509Name object. + * + * @throws WolfSSLException if native API call fails. + */ + public WolfSSLX509Name() throws WolfSSLException { + + x509NamePtr = X509_NAME_new(); + if (x509NamePtr == 0) { + throw new WolfSSLException("Failed to create WolfSSLX509Name"); + } + + synchronized (stateLock) { + this.active = true; + } + } + + /** + * Verifies that the current WolfSSLX509Name object is active. + * + * @throws IllegalStateException if object has been freed + */ + private void confirmObjectIsActive() + throws IllegalStateException { + + synchronized (stateLock) { + if (this.active == false) { + throw new IllegalStateException( + "WolfSSLX509Name object has been freed"); + } + } + } + + /** + * For package use only, return native WOLFSSL_X509_NAME pointer. + * + * @return native WOLFSSL_X509_POINTER value + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + protected long getNativeX509NamePtr() throws IllegalStateException { + + confirmObjectIsActive(); + + /* TODO lock around x509NamePtr */ + return this.x509NamePtr; + } + + /** + * Private helper function to call native JNI function + * X509_NAME_add_entry_by_txt(). + * + * @param field String containing field name to set, for example + * "countryName" + * @param entry String value to store into field + * + * @throws WolfSSLException if arguments are invalid or error occurs + * with native JNI call. + */ + private synchronized void addEntryByTxt(String field, String entry) + throws WolfSSLException { + + int ret = 0; + + if (field == null || entry == null) { + throw new WolfSSLException("field or entry is null in " + + "addEntryByTxt()"); + } + + ret = X509_NAME_add_entry_by_txt(this.x509NamePtr, field, + MBSTRING_UTF8, entry.getBytes(), + entry.getBytes().length, -1, 0); + + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException("Error setting " + field + " into " + + "WolfSSLX509Name (error: " + ret + ")"); + } + } + + /** + * Set country name for this name object. + * + * @param countryName String containing country name to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setCountryName(String countryName) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("countryName", countryName); + this.countryName = countryName; + } + + /** + * Set state or province name for this name object. + * + * @param name String containing state or province name to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setStateOrProvinceName(String name) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("stateOrProvinceName", name); + this.stateOrProvinceName = name; + } + + /** + * Set street address for this name object. + * + * @param address String containing street address to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setStreetAddress(String address) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("streetAddress", address); + this.streetAddress = address; + } + + /** + * Set locality name / city for this name object. + * + * @param name String containing locality name to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setLocalityName(String name) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("localityName", name); + this.localityName = name; + } + + /** + * Set surname for this name object. + * + * @param name String containing surname to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setSurname(String name) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("surname", name); + this.surname = name; + } + + /** + * Set common name for this name object. + * + * @param name String containing common name to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setCommonName(String name) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("commonName", name); + this.commonName = name; + } + + /** + * Set email address for this name object. + * + * @param email String containing email address to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setEmailAddress(String email) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("emailAddress", email); + this.emailAddress = email; + } + + /** + * Set organization name for this name object. + * + * @param name String containing organization name to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setOrganizationName(String name) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("organizationName", name); + this.organizationName = name; + } + + /** + * Set organizational unit name for this name object. + * + * @param name String containing organizational unit name to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setOrganizationalUnitName(String name) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("organizationalUnitName", name); + this.organizationalUnitName = name; + } + + /** + * Set postal code for this name object. + * + * @param code String containing postal code to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setPostalCode(String code) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("postalCode", code); + this.postalCode = code; + } + + /** + * Set user ID for this name object. + * + * @param id String containing user ID to be set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + * @throws WolfSSLException if native JNI error has occurred, or input + * argument is invalid. + */ + public synchronized void setUserId(String id) + throws IllegalStateException, WolfSSLException { + + confirmObjectIsActive(); + + addEntryByTxt("userId", id); + this.userId = id; + } + + /** + * Get country name set in this object. + * + * @return country name string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getCountryName() { + + confirmObjectIsActive(); + + return this.countryName; + } + + /** + * Get state or province name set in this object. + * + * @return state or province name string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getStateOrProvinceName() { + + confirmObjectIsActive(); + + return this.stateOrProvinceName; + } + + /** + * Get street address set in this object. + * + * @return street address string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getStreetAddress() { + + confirmObjectIsActive(); + + return this.streetAddress; + } + + /** + * Get locality name set in this object. + * + * @return locality name string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getLocalityName() { + + confirmObjectIsActive(); + + return this.localityName; + } + + /** + * Get surname set in this object. + * + * @return surname string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getSurname() { + + confirmObjectIsActive(); + + return this.surname; + } + + /** + * Get common name set in this object. + * + * @return common name string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getCommonName() { + + confirmObjectIsActive(); + + return this.commonName; + } + + /** + * Get email address set in this object. + * + * @return email address string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getEmailAddress() { + + confirmObjectIsActive(); + + return this.emailAddress; + } + + /** + * Get organization name set in this object. + * + * @return organization name string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getOrganizationName() { + + confirmObjectIsActive(); + + return this.organizationName; + } + + /** + * Get organizational unit name set in this object. + * + * @return organizational unit name string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getOrganizationalUnitName() { + + confirmObjectIsActive(); + + return this.organizationalUnitName; + } + + /** + * Get postal code set in this object. + * + * @return postal code string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getPostalCode() { + + confirmObjectIsActive(); + + return this.postalCode; + } + + /** + * Get user ID set in this object. + * + * @return user ID string, or null if not yet set + * + * @throws IllegalStateException if WolfSSLX509Name has been freed. + */ + public synchronized String getUserId() { + + confirmObjectIsActive(); + + return this.userId; + } + + @Override + public String toString() { + + synchronized (stateLock) { + if (this.active == false) { + return ""; + } + } + + /* TODO: wrap wolfSSL_X509_NAME_oneline() */ + return null; + } + + /** + * Free native resources of WolfSSLX509Name. + */ + public synchronized void free() { + + synchronized (stateLock) { + if (this.active == false) { + /* already freed, just return */ + return; + } + + /* free native resources */ + X509_NAME_free(this.x509NamePtr); + + this.active = false; + this.x509NamePtr = 0; + } + } + + @SuppressWarnings("deprecation") + @Override + protected void finalize() throws Throwable + { + this.free(); + super.finalize(); + } +} + diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java b/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java index d24fb93b..9b698836 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java @@ -22,6 +22,7 @@ import com.wolfssl.WolfSSLVerifyCallback; import com.wolfssl.WolfSSLException; +import com.wolfssl.WolfSSLJNIException; import com.wolfssl.WolfSSLCertificate; import com.wolfssl.WolfSSLX509StoreCtx; import com.wolfssl.provider.jsse.WolfSSLInternalVerifyCb; @@ -103,7 +104,8 @@ public int verifyCallback(int preverify_ok, long x509StorePtr) { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "Peer cert: " + x509certs[i].getSubjectDN().getName()); } - } catch (CertificateException | IOException ce) { + } catch (CertificateException | IOException | + WolfSSLJNIException ce) { /* failed to get cert array, give app null array */ WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "Failed to get X509Certificate[] array, set to null"); diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java index 8bbe3db4..535819bf 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java @@ -40,6 +40,7 @@ import com.wolfssl.WolfSSL; import com.wolfssl.WolfSSLCertificate; import com.wolfssl.WolfSSLException; +import com.wolfssl.WolfSSLJNIException; /** * wolfSSL implemenation of TrustManagerFactorySpi @@ -346,6 +347,8 @@ protected void engineInit(KeyStore in) throws KeyStoreException { throw new KeyStoreException(ex); } catch (CertificateException ex) { throw new KeyStoreException(ex); + } catch (WolfSSLJNIException ex) { + throw new KeyStoreException(ex); } } this.store = certs; diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java b/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java index 8f5fb34f..dd021b08 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLX509.java @@ -45,6 +45,7 @@ import com.wolfssl.WolfSSLCertificate; import com.wolfssl.WolfSSLException; +import com.wolfssl.WolfSSLJNIException; /** * wolfSSL implementation of X509Certificate @@ -334,11 +335,17 @@ public byte[] getEncoded() throws CertificateEncodingException { if (this.cert == null) { return null; } - byte[] ret = this.cert.getDer(); - if (ret == null) { - throw new CertificateEncodingException(); + + try { + byte[] ret = this.cert.getDer(); + if (ret == null) { + throw new CertificateEncodingException(); + } + return ret; + + } catch (WolfSSLJNIException e) { + throw new CertificateEncodingException(e); } - return ret; } @Override diff --git a/src/test/com/wolfssl/test/WolfSSLCertificateTest.java b/src/test/com/wolfssl/test/WolfSSLCertificateTest.java index ff7d8376..b6c401b1 100644 --- a/src/test/com/wolfssl/test/WolfSSLCertificateTest.java +++ b/src/test/com/wolfssl/test/WolfSSLCertificateTest.java @@ -27,15 +27,37 @@ import java.io.InputStream; import java.math.BigInteger; import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; -import static org.junit.Assert.fail; +import java.time.Instant; +import java.time.Duration; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.interfaces.RSAPrivateKey; +import java.security.KeyPairGenerator; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.PublicKey; +import java.security.PrivateKey; +import java.security.NoSuchAlgorithmException; + import org.junit.Test; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import static org.junit.Assert.*; import com.wolfssl.WolfSSL; +import com.wolfssl.WolfSSLX509Name; import com.wolfssl.WolfSSLCertificate; +import com.wolfssl.WolfSSLCertManager; import com.wolfssl.WolfSSLException; +import com.wolfssl.WolfSSLJNIException; /** * @@ -47,18 +69,38 @@ public class WolfSSLCertificateTest { public static String cliCertDer = "examples/certs/client-cert.der"; public static String cliCertPem = "examples/certs/client-cert.pem"; + public static String cliKeyDer = "examples/certs/client-key.der"; + public static String cliKeyPubDer = "examples/certs/client-keyPub.der"; + public static String caCertPem = "examples/certs/ca-cert.pem"; + public static String caKeyDer = "examples/certs/ca-key.der"; + public static String caKeyPkcs8Der = "examples/certs/ca-keyPkcs8.der"; + public static String serverCertPem = "examples/certs/server-cert.pem"; public static String external = "examples/certs/ca-google-root.der"; public static String bogusFile = "/dev/null"; private WolfSSLCertificate cert; - @Test - public void testWolfSSLCertificate() throws WolfSSLException { + @BeforeClass + public static void setCertPaths() throws WolfSSLException { - System.out.println("WolfSSLCertificate Class"); + try { + WolfSSL.loadLibrary(); + } catch (UnsatisfiedLinkError ule) { + fail("failed to load native JNI library"); + } cliCertDer = WolfSSLTestCommon.getPath(cliCertDer); cliCertPem = WolfSSLTestCommon.getPath(cliCertPem); + cliKeyPubDer = WolfSSLTestCommon.getPath(cliKeyPubDer); + caCertPem = WolfSSLTestCommon.getPath(caCertPem); + caKeyDer = WolfSSLTestCommon.getPath(caKeyDer); external = WolfSSLTestCommon.getPath(external); + } + + + @Test + public void testWolfSSLCertificate() throws WolfSSLException { + + System.out.println("WolfSSLCertificate Class"); /* WolfSSLCertificate(byte[] der) */ test_WolfSSLCertificate_new_derArray(); @@ -79,7 +121,6 @@ public void testWolfSSLCertificate() throws WolfSSLException { } } - public void test_runCertTestsAfterConstructor() { test_getSerial(); test_notBefore(); @@ -95,7 +136,11 @@ public void test_runCertTestsAfterConstructor() { test_getSignatureType(); test_verify(); test_getSignatureOID(); - test_getKeyUsage(); + if (WolfSSL.getLibVersionHex() > 0x05006003) { + /* Key Usage and Extended Key Usage only work with wolfSSL + * later than 5.6.3 */ + test_getKeyUsage(); + } test_getExtensionSet(); test_toString(); test_free(); @@ -208,11 +253,11 @@ private byte[] fileToByteArray(String filePath) public void test_getSerial() { - byte[] expected = new byte[]{ - (byte)0x01, (byte)0x1a, (byte)0xeb, (byte)0x56, (byte)0xab, - (byte)0xdc, (byte)0x8b, (byte)0xf3, (byte)0xa6, (byte)0x1e, - (byte)0xf4, (byte)0x93, (byte)0x60, (byte)0x89, (byte)0xb7, - (byte)0x05, (byte)0x07, (byte)0x29, (byte)0x01, (byte)0x2c + byte[] expected = new byte[] { + (byte)0x73, (byte)0xfb, (byte)0x54, (byte)0xd6, (byte)0x03, + (byte)0x7d, (byte)0x4c, (byte)0x07, (byte)0x84, (byte)0xe2, + (byte)0x00, (byte)0x11, (byte)0x8c, (byte)0xdd, (byte)0x90, + (byte)0xdc, (byte)0x48, (byte)0x8d, (byte)0xea, (byte)0x53 }; byte[] serial; int i; @@ -232,7 +277,7 @@ public void test_getSerial() { @SuppressWarnings("deprecation") public void test_notBefore() { Date date = cert.notBefore(); - Date expected = new Date("Feb 15 12:50:24 2022 GMT"); + Date expected = new Date("Dec 16 21:17:49 2022 GMT"); System.out.print("\t\tnotBefore"); if (date.compareTo(expected) != 0) { System.out.println("\t\t... failed"); @@ -245,7 +290,7 @@ public void test_notBefore() { @SuppressWarnings("deprecation") public void test_notAfter() { Date date = cert.notAfter(); - Date expected = new Date("Nov 11 12:50:24 2024 GMT"); + Date expected = new Date("Sep 11 21:17:49 2025 GMT"); System.out.print("\t\tnotAfter"); if (date.compareTo(expected) != 0) { System.out.println("\t\t... failed"); @@ -268,49 +313,58 @@ public void test_getVersion() { public void test_getSignature() { byte[] sig = cert.getSignature(); byte[] expected = new byte[] { - (byte)0x64, (byte)0x6d, (byte)0xa6, (byte)0x4a, (byte)0xa8, (byte)0x9f, - (byte)0xa7, (byte)0xe9, (byte)0x75, (byte)0x2c, (byte)0xf3, (byte)0x85, - (byte)0x3d, (byte)0x3e, (byte)0xaf, (byte)0x38, (byte)0xfb, (byte)0x6c, - (byte)0xc7, (byte)0xeb, (byte)0xc7, (byte)0xd0, (byte)0x2b, (byte)0xa2, - (byte)0x45, (byte)0xb5, (byte)0x65, (byte)0xbe, (byte)0xd0, (byte)0x13, - (byte)0x2c, (byte)0xf7, (byte)0xa3, (byte)0xc1, (byte)0xeb, (byte)0x3c, - (byte)0xb1, (byte)0xf8, (byte)0xb8, (byte)0x3d, (byte)0x63, (byte)0x8f, - (byte)0xca, (byte)0x08, (byte)0x4e, (byte)0x65, (byte)0x1d, (byte)0x2c, - (byte)0xce, (byte)0x34, (byte)0x6e, (byte)0x35, (byte)0x96, (byte)0x87, - (byte)0x93, (byte)0x30, (byte)0x5d, (byte)0xaa, (byte)0xc8, (byte)0xe9, - (byte)0xa0, (byte)0x9c, (byte)0x9b, (byte)0x84, (byte)0x78, (byte)0x3a, - (byte)0x52, (byte)0xa1, (byte)0x33, (byte)0x48, (byte)0x6e, (byte)0x84, - (byte)0x66, (byte)0x71, (byte)0x9c, (byte)0xcf, (byte)0xd1, (byte)0xc7, - (byte)0x7b, (byte)0x02, (byte)0x4c, (byte)0xe1, (byte)0x49, (byte)0x7c, - (byte)0x69, (byte)0x47, (byte)0xfc, (byte)0xb7, (byte)0x01, (byte)0xf9, - (byte)0xa0, (byte)0x39, (byte)0x3b, (byte)0xab, (byte)0xb9, (byte)0xc6, - (byte)0xd9, (byte)0xca, (byte)0x27, (byte)0x85, (byte)0xf0, (byte)0x5c, - (byte)0xb6, (byte)0xa4, (byte)0xe6, (byte)0xdc, (byte)0xf2, (byte)0x52, - (byte)0xfe, (byte)0x44, (byte)0x00, (byte)0xb6, (byte)0xf0, (byte)0x47, - (byte)0xf2, (byte)0x6f, (byte)0x3f, (byte)0xd5, (byte)0x0f, (byte)0xff, - (byte)0x31, (byte)0x93, (byte)0x53, (byte)0x88, (byte)0x8c, (byte)0xc7, - (byte)0xfb, (byte)0x56, (byte)0x10, (byte)0x4b, (byte)0x3b, (byte)0x43, - (byte)0xe6, (byte)0x8a, (byte)0x9c, (byte)0xb7, (byte)0xb4, (byte)0x9a, - (byte)0xdd, (byte)0x5c, (byte)0xe3, (byte)0xcd, (byte)0x9c, (byte)0xbd, - (byte)0xa7, (byte)0x0c, (byte)0xc1, (byte)0xd9, (byte)0x96, (byte)0xf0, - (byte)0x93, (byte)0xf3, (byte)0xab, (byte)0xbd, (byte)0xd2, (byte)0x1e, - (byte)0x77, (byte)0x8a, (byte)0x42, (byte)0xcd, (byte)0x0f, (byte)0xfe, - (byte)0x48, (byte)0xda, (byte)0x57, (byte)0x34, (byte)0x61, (byte)0x46, - (byte)0xa3, (byte)0x89, (byte)0x2e, (byte)0x31, (byte)0xd2, (byte)0x4a, - (byte)0xd4, (byte)0x43, (byte)0x2f, (byte)0x56, (byte)0x85, (byte)0x44, - (byte)0x75, (byte)0xca, (byte)0x6b, (byte)0x36, (byte)0xe2, (byte)0xe8, - (byte)0x3a, (byte)0xb2, (byte)0x95, (byte)0x95, (byte)0x3a, (byte)0x28, - (byte)0x90, (byte)0x8d, (byte)0xc0, (byte)0x23, (byte)0xfb, (byte)0x3c, - (byte)0xd2, (byte)0x1a, (byte)0x73, (byte)0x6b, (byte)0xef, (byte)0xfd, - (byte)0xd6, (byte)0x1b, (byte)0xeb, (byte)0x6d, (byte)0x67, (byte)0x2a, - (byte)0xe1, (byte)0xeb, (byte)0x2a, (byte)0x83, (byte)0x22, (byte)0xad, - (byte)0xe3, (byte)0x95, (byte)0x19, (byte)0xe5, (byte)0x93, (byte)0xee, - (byte)0x14, (byte)0xdc, (byte)0xb5, (byte)0x7d, (byte)0xe7, (byte)0xcf, - (byte)0x89, (byte)0x8c, (byte)0xd7, (byte)0x8f, (byte)0xd2, (byte)0x3f, - (byte)0x68, (byte)0x7e, (byte)0xa9, (byte)0x74, (byte)0x7c, (byte)0x1b, - (byte)0x38, (byte)0x65, (byte)0xf9, (byte)0x28, (byte)0x4d, (byte)0xff, - (byte)0x50, (byte)0xc8, (byte)0xee, (byte)0x51, (byte)0x3a, (byte)0x8f, - (byte)0x1d, (byte)0x9e, (byte)0x55, (byte)0x5e + (byte)0x36, (byte)0xcb, (byte)0xbc, (byte)0xc5, (byte)0x52, + (byte)0x9a, (byte)0x66, (byte)0xcd, (byte)0x91, (byte)0x4d, + (byte)0x8f, (byte)0x27, (byte)0x9f, (byte)0xb3, (byte)0x64, + (byte)0x80, (byte)0x0e, (byte)0x64, (byte)0xb4, (byte)0xcb, + (byte)0x1a, (byte)0xcd, (byte)0x75, (byte)0x9e, (byte)0x82, + (byte)0x7c, (byte)0x55, (byte)0x67, (byte)0xd8, (byte)0x9f, + (byte)0x90, (byte)0xa3, (byte)0x34, (byte)0x96, (byte)0x99, + (byte)0x43, (byte)0xf7, (byte)0x49, (byte)0x53, (byte)0xa2, + (byte)0x58, (byte)0x85, (byte)0xa0, (byte)0xb3, (byte)0x83, + (byte)0x4f, (byte)0xaf, (byte)0xb8, (byte)0x15, (byte)0x8a, + (byte)0x88, (byte)0x1e, (byte)0xf3, (byte)0x60, (byte)0xf4, + (byte)0x7c, (byte)0x94, (byte)0xb5, (byte)0x58, (byte)0x68, + (byte)0xf1, (byte)0x2a, (byte)0x13, (byte)0x80, (byte)0x34, + (byte)0xc2, (byte)0x6f, (byte)0xa5, (byte)0xf8, (byte)0x7e, + (byte)0x76, (byte)0x16, (byte)0x81, (byte)0x4f, (byte)0x36, + (byte)0x8b, (byte)0xc3, (byte)0x59, (byte)0xbd, (byte)0x51, + (byte)0xdd, (byte)0x60, (byte)0x87, (byte)0xd7, (byte)0x1d, + (byte)0x96, (byte)0x44, (byte)0x69, (byte)0x07, (byte)0x3c, + (byte)0x8f, (byte)0x28, (byte)0x56, (byte)0xb1, (byte)0x11, + (byte)0x5c, (byte)0x4e, (byte)0x81, (byte)0x3f, (byte)0x57, + (byte)0x25, (byte)0xfd, (byte)0x65, (byte)0xdd, (byte)0x07, + (byte)0xcf, (byte)0x17, (byte)0x0a, (byte)0x01, (byte)0x7e, + (byte)0x4e, (byte)0x3f, (byte)0x8e, (byte)0x73, (byte)0xdb, + (byte)0xfe, (byte)0xf4, (byte)0xf2, (byte)0xc5, (byte)0xff, + (byte)0xa3, (byte)0x76, (byte)0xa8, (byte)0x74, (byte)0x46, + (byte)0x2e, (byte)0x47, (byte)0x0d, (byte)0xb0, (byte)0xed, + (byte)0x0a, (byte)0xc0, (byte)0xc5, (byte)0x0a, (byte)0x65, + (byte)0xd3, (byte)0xdc, (byte)0x62, (byte)0xb2, (byte)0xe0, + (byte)0x1e, (byte)0x8e, (byte)0xbd, (byte)0xf3, (byte)0xbd, + (byte)0xaf, (byte)0xaf, (byte)0x66, (byte)0x84, (byte)0x36, + (byte)0x92, (byte)0xe2, (byte)0x3b, (byte)0x80, (byte)0xd0, + (byte)0x57, (byte)0xa6, (byte)0x41, (byte)0xa3, (byte)0x62, + (byte)0xd1, (byte)0xa6, (byte)0x6d, (byte)0x14, (byte)0x6c, + (byte)0xcd, (byte)0x82, (byte)0xb1, (byte)0xc1, (byte)0xc1, + (byte)0x35, (byte)0x55, (byte)0xae, (byte)0x59, (byte)0x49, + (byte)0xa8, (byte)0x26, (byte)0x52, (byte)0xbd, (byte)0xef, + (byte)0x1b, (byte)0x2c, (byte)0x1f, (byte)0x9d, (byte)0x39, + (byte)0x04, (byte)0xd2, (byte)0x82, (byte)0xa0, (byte)0x6b, + (byte)0x39, (byte)0x71, (byte)0x59, (byte)0x33, (byte)0x82, + (byte)0xba, (byte)0x55, (byte)0x6c, (byte)0x97, (byte)0xf2, + (byte)0x1b, (byte)0x5b, (byte)0xe0, (byte)0x4d, (byte)0xe2, + (byte)0xcf, (byte)0x89, (byte)0xe7, (byte)0x26, (byte)0xb8, + (byte)0x2c, (byte)0x6c, (byte)0x9f, (byte)0x83, (byte)0xd6, + (byte)0xed, (byte)0x4e, (byte)0x2f, (byte)0x75, (byte)0xa9, + (byte)0x30, (byte)0x4e, (byte)0x01, (byte)0x95, (byte)0x0d, + (byte)0x4f, (byte)0x83, (byte)0x5e, (byte)0xc8, (byte)0xaf, + (byte)0x7f, (byte)0x67, (byte)0xea, (byte)0x53, (byte)0xbf, + (byte)0xca, (byte)0x9b, (byte)0x1f, (byte)0xd4, (byte)0xff, + (byte)0x36, (byte)0x97, (byte)0x02, (byte)0x71, (byte)0x8e, + (byte)0x33, (byte)0xde, (byte)0xe2, (byte)0x58, (byte)0x27, + (byte)0xaa, (byte)0x70, (byte)0x0c, (byte)0x5b, (byte)0xde, + (byte)0x0e }; int i; System.out.print("\t\tgetSignature"); @@ -577,4 +631,616 @@ public void test_free() { this.cert.free(); System.out.println("\t\t\t... passed"); } + + @Test + public void testWolfSSLCertificateGeneration() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException, NoSuchAlgorithmException, + InvalidKeySpecException { + + System.out.println("WolfSSLCertificate Generation"); + + if (WolfSSL.FileSystemEnabled() == true) { + testCertGen_SelfSigned_UsingFiles(); + testCertGen_SelfSigned_UsingBuffers(); + testCertGen_SelfSigned_UsingJavaClasses(); + testCertGen_CASigned_UsingFiles(); + testCertGen_CASigned_UsingBuffers(); + testCertGen_CASigned_UsingJavaClasses(); + } + } + + /* Quick sanity check on certificate bytes. Loads cert into new + * WolfSSLCertificate object, tries to get various elements and + * simply verify if not null / etc. */ + private void sanityCheckCertFileBytes(byte[] certBytes, int type) + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException { + + if (certBytes == null || + (type != WolfSSL.SSL_FILETYPE_ASN1 && + type != WolfSSL.SSL_FILETYPE_PEM)) { + throw new WolfSSLException("certBytes is null or bad type"); + } + + WolfSSLCertificate tmp = new WolfSSLCertificate(certBytes, type); + assertNotNull(tmp); + assertNotNull(tmp.getDer()); + assertNotNull(tmp.getPem()); + assertNotNull(tmp.getTbs()); + assertNotNull(tmp.getSerial()); + assertNotNull(tmp.notBefore()); + assertNotNull(tmp.notAfter()); + assertTrue(tmp.getVersion() >= 0); + assertNotNull(tmp.getSignature()); + assertNotNull(tmp.getSignatureType()); + assertNotNull(tmp.getSignatureOID()); + assertNotNull(tmp.getPubkey()); + assertNotNull(tmp.getPubkeyType()); + int isCA = tmp.isCA(); + assertTrue(isCA == 0 || isCA == 1); + assertTrue(tmp.getPathLen() >= -1); + assertNotNull(tmp.getSubject()); + assertNotNull(tmp.getIssuer()); + if (WolfSSL.getLibVersionHex() > 0x05006003) { + /* Key Usage and Extended Key Usage only work with wolfSSL + * later than 5.6.3 */ + assertNotNull(tmp.getKeyUsage()); + } + assertNotNull(tmp.getSubjectAltNames()); + assertNotNull(tmp.getX509Certificate()); + assertNotNull(tmp.toString()); + } + + /* Make sure peer cert can be verified using CertManager and provided + * CA cert (and optional intermediate CA cert if needed). Supports PEM and + * DER. Throws WolfSSLException if not valid. */ + private void verifyCertSignatureIsCorrect( + byte[] peerCert, int peerCertType, + byte[] intCaCert, int intCaCertType, + byte[] rootCaCert, int rootCaCertType) throws WolfSSLException { + + int ret = WolfSSL.SSL_FAILURE; + WolfSSLCertManager cm = new WolfSSLCertManager(); + + if (peerCert == null || rootCaCert == null || + (peerCertType != WolfSSL.SSL_FILETYPE_ASN1 && + peerCertType != WolfSSL.SSL_FILETYPE_PEM) || + (rootCaCertType != WolfSSL.SSL_FILETYPE_ASN1 && + rootCaCertType != WolfSSL.SSL_FILETYPE_PEM)) { + throw new WolfSSLException("cert or CA cert is null or bad type"); + } + + /* Load root CA as trusted */ + ret = cm.CertManagerLoadCABuffer(rootCaCert, rootCaCert.length, + rootCaCertType); + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException("Failed to load CA for verifying"); + } + + /* Load intermediate CA as trusted if needed */ + if (intCaCert != null) { + if (intCaCertType != WolfSSL.SSL_FILETYPE_ASN1 && + intCaCertType != WolfSSL.SSL_FILETYPE_PEM) { + throw new WolfSSLException("intermediate cert is bad type"); + } + + ret = cm.CertManagerLoadCABuffer(intCaCert, intCaCert.length, + intCaCertType); + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException( + "Failed to load intermediate CA for verifying"); + } + } + + ret = cm.CertManagerVerifyBuffer(peerCert, peerCert.length, + peerCertType); + if (ret != WolfSSL.SSL_SUCCESS) { + throw new WolfSSLException("Failed to verify peer cert against CA"); + } + } + + + /* Internal helper method, generate test SubjectName for cert generation */ + private WolfSSLX509Name GenerateTestSubjectName() throws WolfSSLException { + + WolfSSLX509Name name = new WolfSSLX509Name(); + + name.setCountryName("US"); + name.setStateOrProvinceName("Montana"); + name.setStreetAddress("12345 Test Address"); + name.setLocalityName("Bozeman"); + name.setSurname("Test Surname"); + name.setCommonName("wolfssl.com"); + name.setEmailAddress("support@wolfssl.com"); + name.setOrganizationName("wolfSSL Inc."); + name.setOrganizationalUnitName("Development Test"); + name.setUserId("TestUserID"); + + return name; + } + + /* Test self-signed certificate generation using files for public key, + * issuer name, and issuer private key */ + private void testCertGen_SelfSigned_UsingFiles() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException { + + System.out.print("\tself signed (files)"); + + WolfSSLCertificate x509 = new WolfSSLCertificate(); + assertNotNull(x509); + + /* Set notBefore/notAfter dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = GenerateTestSubjectName(); + assertNotNull(subjectName); + x509.setSubjectName(subjectName); + + /* Not setting Issuer, since generating self-signed cert */ + + /* Set Public Key from file */ + x509.setPublicKey(cliKeyPubDer, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1); + + /* Set Extensions */ + if (WolfSSL.getLibVersionHex() > 0x05006003) { + /* Key Usage and Extended Key Usage only work with wolfSSL + * later than 5.6.3 */ + x509.addExtension(WolfSSL.NID_key_usage, + "digitalSignature,keyEncipherment,dataEncipherment", false); + + x509.addExtension(WolfSSL.NID_ext_key_usage, + "clientAuth,serverAuth", false); + } + x509.addExtension(WolfSSL.NID_subject_alt_name, + "test.wolfssl.com", false); + x509.addExtension(WolfSSL.NID_basic_constraints, true, true); + + /* Sign cert, self-signed */ + x509.signCert(cliKeyDer, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1, "SHA256"); + + /* Output to DER and PEM */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + assertNotNull(derCert); + assertTrue(derCert.length > 0); + assertNotNull(pemCert); + assertTrue(pemCert.length > 0); + + /* Sanity check generated cert buffers */ + sanityCheckCertFileBytes(derCert, WolfSSL.SSL_FILETYPE_ASN1); + sanityCheckCertFileBytes(pemCert, WolfSSL.SSL_FILETYPE_PEM); + + /* Sanity check CertManager can verify signature using expected CA */ + verifyCertSignatureIsCorrect(derCert, WolfSSL.SSL_FILETYPE_ASN1, + null, 0, derCert, WolfSSL.SSL_FILETYPE_ASN1); + verifyCertSignatureIsCorrect(pemCert, WolfSSL.SSL_FILETYPE_PEM, + null, 0, derCert, WolfSSL.SSL_FILETYPE_ASN1); + + /* Free native memory */ + subjectName.free(); + x509.free(); + + System.out.println("\t\t... passed"); + } + + /* Test CA-signed certificate generation using files for public key, + * issuer name, and issuer private key */ + private void testCertGen_CASigned_UsingFiles() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException { + + System.out.print("\tCA signed (files)"); + + WolfSSLCertificate x509 = new WolfSSLCertificate(); + assertNotNull(x509); + + /* Set notBefore/notAfter dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = GenerateTestSubjectName(); + assertNotNull(subjectName); + x509.setSubjectName(subjectName); + + /* Set Issuer Name from existing PEM file */ + WolfSSLCertificate issuer = + new WolfSSLCertificate(caCertPem, WolfSSL.SSL_FILETYPE_PEM); + x509.setIssuerName(issuer); + + /* Set Public Key from file */ + x509.setPublicKey(cliKeyPubDer, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1); + + /* Set Extensions */ + if (WolfSSL.getLibVersionHex() > 0x05006003) { + /* Key Usage and Extended Key Usage only work with wolfSSL + * later than 5.6.3 */ + x509.addExtension(WolfSSL.NID_key_usage, + "digitalSignature,keyEncipherment,dataEncipherment", false); + x509.addExtension(WolfSSL.NID_ext_key_usage, + "clientAuth,serverAuth", false); + } + x509.addExtension(WolfSSL.NID_subject_alt_name, + "test.wolfssl.com", false); + x509.addExtension(WolfSSL.NID_basic_constraints, false, true); + + /* Sign cert, CA-signed */ + x509.signCert(caKeyDer, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1, "SHA256"); + + /* Output to DER and PEM */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + assertNotNull(derCert); + assertTrue(derCert.length > 0); + assertNotNull(pemCert); + assertTrue(pemCert.length > 0); + + /* Sanity check generated cert buffers */ + sanityCheckCertFileBytes(derCert, WolfSSL.SSL_FILETYPE_ASN1); + sanityCheckCertFileBytes(pemCert, WolfSSL.SSL_FILETYPE_PEM); + + /* Sanity check CertManager can verify signature using expected CA */ + verifyCertSignatureIsCorrect(derCert, WolfSSL.SSL_FILETYPE_ASN1, + null, 0, issuer.getDer(), WolfSSL.SSL_FILETYPE_ASN1); + verifyCertSignatureIsCorrect(pemCert, WolfSSL.SSL_FILETYPE_PEM, + null, 0, issuer.getDer(), WolfSSL.SSL_FILETYPE_ASN1); + + /* Free native memory */ + subjectName.free(); + x509.free(); + + System.out.println("\t\t... passed"); + } + + /* Test self-signed certificate generation using buffers for public key, + * issuer name, and issuer private key */ + private void testCertGen_SelfSigned_UsingBuffers() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException { + + System.out.print("\tself signed (buffers)"); + + WolfSSLCertificate x509 = new WolfSSLCertificate(); + assertNotNull(x509); + + /* Set notBefore/notAfter dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = GenerateTestSubjectName(); + assertNotNull(subjectName); + x509.setSubjectName(subjectName); + + /* Not setting Issuer, since generating self-signed cert */ + + /* Set Public Key from file */ + byte[] pubKey = Files.readAllBytes(Paths.get(cliKeyPubDer)); + x509.setPublicKey(pubKey, WolfSSL.RSAk, WolfSSL.SSL_FILETYPE_ASN1); + + /* Set Extensions */ + if (WolfSSL.getLibVersionHex() > 0x05006003) { + /* Key Usage and Extended Key Usage only work with wolfSSL + * later than 5.6.3 */ + x509.addExtension(WolfSSL.NID_key_usage, + "digitalSignature,keyEncipherment,dataEncipherment", false); + x509.addExtension(WolfSSL.NID_ext_key_usage, + "clientAuth,serverAuth", false); + } + x509.addExtension(WolfSSL.NID_subject_alt_name, + "test.wolfssl.com", false); + x509.addExtension(WolfSSL.NID_basic_constraints, true, true); + + /* Sign cert, self-signed */ + byte[] privKey = Files.readAllBytes(Paths.get(cliKeyDer)); + x509.signCert(privKey, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1, "SHA256"); + + /* Output to DER and PEM */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + assertNotNull(derCert); + assertTrue(derCert.length > 0); + assertNotNull(pemCert); + assertTrue(pemCert.length > 0); + + /* Sanity check generated cert buffers */ + sanityCheckCertFileBytes(derCert, WolfSSL.SSL_FILETYPE_ASN1); + sanityCheckCertFileBytes(pemCert, WolfSSL.SSL_FILETYPE_PEM); + + /* Sanity check CertManager can verify signature using expected CA */ + verifyCertSignatureIsCorrect(derCert, WolfSSL.SSL_FILETYPE_ASN1, + null, 0, derCert, WolfSSL.SSL_FILETYPE_ASN1); + verifyCertSignatureIsCorrect(pemCert, WolfSSL.SSL_FILETYPE_PEM, + null, 0, derCert, WolfSSL.SSL_FILETYPE_ASN1); + + /* Free native memory */ + subjectName.free(); + x509.free(); + + System.out.println("\t\t... passed"); + } + + /* Test CA-signed certificate generation using buffers for public key, + * issuer name, and issuer private key */ + private void testCertGen_CASigned_UsingBuffers() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException { + + System.out.print("\tCA signed (buffers)"); + + WolfSSLCertificate x509 = new WolfSSLCertificate(); + assertNotNull(x509); + + /* Set notBefore/notAfter dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = GenerateTestSubjectName(); + assertNotNull(subjectName); + x509.setSubjectName(subjectName); + + /* Set Issuer Name from existing PEM file */ + WolfSSLCertificate issuer = + new WolfSSLCertificate(Files.readAllBytes(Paths.get(caCertPem)), + WolfSSL.SSL_FILETYPE_PEM); + x509.setIssuerName(issuer); + + /* Set Public Key from file */ + byte[] pubKey = Files.readAllBytes(Paths.get(cliKeyPubDer)); + x509.setPublicKey(pubKey, WolfSSL.RSAk, WolfSSL.SSL_FILETYPE_ASN1); + + /* Set Extensions */ + if (WolfSSL.getLibVersionHex() > 0x05006003) { + /* Key Usage and Extended Key Usage only work with wolfSSL + * later than 5.6.3 */ + x509.addExtension(WolfSSL.NID_key_usage, + "digitalSignature,keyEncipherment,dataEncipherment", false); + x509.addExtension(WolfSSL.NID_ext_key_usage, + "clientAuth,serverAuth", false); + } + x509.addExtension(WolfSSL.NID_subject_alt_name, + "test.wolfssl.com", false); + x509.addExtension(WolfSSL.NID_basic_constraints, false, true); + + /* Sign cert, CA-signed */ + byte[] privKey = Files.readAllBytes(Paths.get(caKeyDer)); + x509.signCert(privKey, WolfSSL.RSAk, + WolfSSL.SSL_FILETYPE_ASN1, "SHA256"); + + /* Output to DER and PEM */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + assertNotNull(derCert); + assertTrue(derCert.length > 0); + assertNotNull(pemCert); + assertTrue(pemCert.length > 0); + + /* Sanity check generated cert buffers */ + sanityCheckCertFileBytes(derCert, WolfSSL.SSL_FILETYPE_ASN1); + sanityCheckCertFileBytes(pemCert, WolfSSL.SSL_FILETYPE_PEM); + + /* Sanity check CertManager can verify signature using expected CA */ + verifyCertSignatureIsCorrect(derCert, WolfSSL.SSL_FILETYPE_ASN1, + null, 0, issuer.getDer(), WolfSSL.SSL_FILETYPE_ASN1); + verifyCertSignatureIsCorrect(pemCert, WolfSSL.SSL_FILETYPE_PEM, + null, 0, issuer.getDer(), WolfSSL.SSL_FILETYPE_ASN1); + + /* Free native memory */ + subjectName.free(); + x509.free(); + + System.out.println("\t\t... passed"); + } + + /* Test self-signed certificate generation using higher-level Java classes + * for public key, issuer name, and issuer private key */ + private void testCertGen_SelfSigned_UsingJavaClasses() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException, NoSuchAlgorithmException { + + System.out.print("\tself signed (Java classes)"); + + WolfSSLCertificate x509 = new WolfSSLCertificate(); + assertNotNull(x509); + + /* Set notBefore/notAfter dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = GenerateTestSubjectName(); + assertNotNull(subjectName); + x509.setSubjectName(subjectName); + + /* Not setting Issuer, since generating self-signed cert */ + + /* Set Public Key from generated java.security.PublicKey */ + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(2048); + KeyPair keyPair = kpg.generateKeyPair(); + PublicKey pubKey = keyPair.getPublic(); + x509.setPublicKey(pubKey); + + /* Set Extensions */ + if (WolfSSL.getLibVersionHex() > 0x05006003) { + /* Key Usage and Extended Key Usage only work with wolfSSL + * later than 5.6.3 */ + x509.addExtension(WolfSSL.NID_key_usage, + "digitalSignature,keyEncipherment,dataEncipherment", false); + x509.addExtension(WolfSSL.NID_ext_key_usage, + "clientAuth,serverAuth", false); + } + x509.addExtension(WolfSSL.NID_subject_alt_name, + "test.wolfssl.com", false); + x509.addExtension(WolfSSL.NID_basic_constraints, true, true); + + /* Sign cert, self-signed with java.security.PrivateKey */ + PrivateKey privKey = keyPair.getPrivate(); + x509.signCert(privKey, "SHA256"); + + /* Output to DER and PEM */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + assertNotNull(derCert); + assertTrue(derCert.length > 0); + assertNotNull(pemCert); + assertTrue(pemCert.length > 0); + + /* Sanity check generated cert buffers */ + sanityCheckCertFileBytes(derCert, WolfSSL.SSL_FILETYPE_ASN1); + sanityCheckCertFileBytes(pemCert, WolfSSL.SSL_FILETYPE_PEM); + + /* Sanity check CertManager can verify signature using expected CA */ + verifyCertSignatureIsCorrect(derCert, WolfSSL.SSL_FILETYPE_ASN1, + null, 0, derCert, WolfSSL.SSL_FILETYPE_ASN1); + verifyCertSignatureIsCorrect(pemCert, WolfSSL.SSL_FILETYPE_PEM, + null, 0, derCert, WolfSSL.SSL_FILETYPE_ASN1); + + /* Free native memory */ + subjectName.free(); + x509.free(); + + System.out.println("\t... passed"); + } + + /* Test CA-signed certificate generation using higher-level Java classes + * for public key, issuer name, and issuer private key */ + private void testCertGen_CASigned_UsingJavaClasses() + throws WolfSSLException, WolfSSLJNIException, IOException, + CertificateException, NoSuchAlgorithmException, + InvalidKeySpecException { + + System.out.print("\tCA signed (Java classes)"); + + WolfSSLCertificate x509 = new WolfSSLCertificate(); + assertNotNull(x509); + + /* Set notBefore/notAfter dates */ + Instant now = Instant.now(); + final Date notBefore = Date.from(now); + final Date notAfter = Date.from(now.plus(Duration.ofDays(365))); + x509.setNotBefore(notBefore); + x509.setNotAfter(notAfter); + + /* Set serial number */ + x509.setSerialNumber(BigInteger.valueOf(12345)); + + /* Set Subject Name */ + WolfSSLX509Name subjectName = GenerateTestSubjectName(); + assertNotNull(subjectName); + x509.setSubjectName(subjectName); + + /* Set Issuer Name from existing PEM file, using server cert since it + * is a CA, and wolfSSL proper ships a PKCS#8 encoded DER private key + * needed below */ + WolfSSLCertificate issuer = + new WolfSSLCertificate(Files.readAllBytes(Paths.get(caCertPem)), + WolfSSL.SSL_FILETYPE_PEM); + X509Certificate issuerX509 = issuer.getX509Certificate(); + x509.setIssuerName(issuerX509); + + /* Set Public Key from generated java.security.PublicKey */ + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(2048); + KeyPair keyPair = kpg.generateKeyPair(); + PublicKey pubKey = keyPair.getPublic(); + x509.setPublicKey(pubKey); + + /* Set Extensions */ + if (WolfSSL.getLibVersionHex() > 0x05006003) { + /* Key Usage and Extended Key Usage only work with wolfSSL + * later than 5.6.3 */ + x509.addExtension(WolfSSL.NID_key_usage, + "digitalSignature,keyEncipherment,dataEncipherment", false); + x509.addExtension(WolfSSL.NID_ext_key_usage, + "clientAuth,serverAuth", false); + } + x509.addExtension(WolfSSL.NID_subject_alt_name, + "test.wolfssl.com", false); + x509.addExtension(WolfSSL.NID_basic_constraints, false, true); + + /* Sign cert, with CA's private key */ + byte[] privBytes = Files.readAllBytes(Paths.get(caKeyPkcs8Der)); + KeyFactory kf = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privBytes); + RSAPrivateKey rsaPriv = (RSAPrivateKey)kf.generatePrivate(spec); + x509.signCert((PrivateKey)rsaPriv, "SHA256"); + + /* Output to DER and PEM */ + byte[] derCert = x509.getDer(); + byte[] pemCert = x509.getPem(); + + assertNotNull(derCert); + assertTrue(derCert.length > 0); + assertNotNull(pemCert); + assertTrue(pemCert.length > 0); + + /* Sanity check generated cert buffers */ + sanityCheckCertFileBytes(derCert, WolfSSL.SSL_FILETYPE_ASN1); + sanityCheckCertFileBytes(pemCert, WolfSSL.SSL_FILETYPE_PEM); + + /* Sanity check CertManager can verify signature using expected CA */ + verifyCertSignatureIsCorrect(derCert, WolfSSL.SSL_FILETYPE_ASN1, + null, 0, issuer.getDer(), WolfSSL.SSL_FILETYPE_ASN1); + verifyCertSignatureIsCorrect(pemCert, WolfSSL.SSL_FILETYPE_PEM, + null, 0, issuer.getDer(), WolfSSL.SSL_FILETYPE_ASN1); + + /* Free native memory */ + subjectName.free(); + x509.free(); + + System.out.println("\t... passed"); + } + + /* Utility method if needed for testing, print out cert array to file */ + private void writeOutCertFile(byte[] cert, String path) + throws IOException { + Files.write(new File(path).toPath(), cert); + } } + diff --git a/src/test/com/wolfssl/test/WolfSSLTest.java b/src/test/com/wolfssl/test/WolfSSLTest.java index 353a006b..cb183c39 100644 --- a/src/test/com/wolfssl/test/WolfSSLTest.java +++ b/src/test/com/wolfssl/test/WolfSSLTest.java @@ -52,6 +52,7 @@ public void testWolfSSL() throws WolfSSLException { test_WolfSSL_new(lib); test_WolfSSL_protocol(); test_WolfSSL_Method_Allocators(lib); + test_WolfSSL_getLibVersionHex(); testGetCiphersAvailableIana(); } @@ -128,5 +129,17 @@ public void testGetCiphersAvailableIana() { System.out.println("\t... passed"); } + + public void test_WolfSSL_getLibVersionHex() { + System.out.print("\tgetLibVersionHex()"); + + long verHex = WolfSSL.getLibVersionHex(); + if (verHex == 0 || verHex < 0) { + System.out.println("\t\t... failed"); + fail("getting library version hex failed"); + } + + System.out.println("\t\t... passed"); + } } From 61cd4523d12f7fbe6e0fd77092b6d07cd35256f8 Mon Sep 17 00:00:00 2001 From: Chris Conlon Date: Fri, 28 Jul 2023 16:39:12 -0600 Subject: [PATCH 2/2] Windows: add .bat scripts for running X509 and ProviderTest example --- IDE/WIN/README.md | 33 +++++++++++++++++++ examples/WindowsConfig.bat | 42 ++++++++++++++++++++++++ examples/X509v3CertificateGeneration.bat | 14 ++++++++ examples/provider/ProviderTest.bat | 14 ++++++++ 4 files changed, 103 insertions(+) create mode 100644 examples/WindowsConfig.bat create mode 100644 examples/X509v3CertificateGeneration.bat create mode 100644 examples/provider/ProviderTest.bat diff --git a/IDE/WIN/README.md b/IDE/WIN/README.md index 6f3ba2f5..33997b6a 100644 --- a/IDE/WIN/README.md +++ b/IDE/WIN/README.md @@ -391,4 +391,37 @@ ant test-win32-release-fips ant test-win64-debug-fips ant test-win64-release-fips ``` +# Running Examples + +Windows batch scripts have been included to easily run some of the provided +examples from the Windows command line. + +After the above steps have been followed to compile native wolfSSL and +wolfSSL JNI/JSSE, open a Command Prompt and navigate to the wolfSSL JNI/JSSE +directory root (ie: wolfssljni). + +Compile the examples: + +``` +ant examples +``` + +Edit the Windows configuration batch script to set the appropriate paths +for native wolfSSL and wolfSSL JNI DLL locations. This can change between +build types (ex: normal wolfSSL, FIPS 140-2, etc): + +**Edit examples\WindowsConfig.bat** + +From the root wolfssljni directory, run the desired .bat file. For example, +to run the ProviderTest: + +``` +examples\provider\ProviderTest.bat +``` + +Or to run the X509v3 certificate generation example: + +``` +examples\X509v3CertificateGeneration.bat +``` diff --git a/examples/WindowsConfig.bat b/examples/WindowsConfig.bat new file mode 100644 index 00000000..a093e2a3 --- /dev/null +++ b/examples/WindowsConfig.bat @@ -0,0 +1,42 @@ + +:: ----------------------------------------------------------------------------- +:: Build Configuration +:: ----------------------------------------------------------------------------- + +:: Set below directories containing native wolfSSL DLL and wolfSSL JNI DLL +:: Default pathing expects wolfssl and wolfssljni dirs to be side by side +:: May uncomment / comment lines below that match your build. This file is +:: included by other example .bat files. + +:: wolfSSL Normal non-FIPS (DLL Debug x64) +SET WOLFSSL_DLL_DIR=..\..\..\wolfssl\IDE\WIN10\DLL Debug\x64 +SET WOLFSSLJNI_DLL_DIR=..\..\IDE\WIN\DLL Debug\x64 + +:: wolfSSL Normal non-FIPS (DLL Release x64) +:: SET WOLFSSL_DLL_DIR=..\..\..\wolfssl\IDE\WIN10\DLL Release\x64 +:: SET WOLFSSLJNI_DLL_DIR=..\..\IDE\WIN\DLL Release\x64 + +:: wolfSSL Normal non-FIPS (DLL Debug Win32) +:: SET WOLFSSL_DLL_DIR=..\..\..\wolfssl\IDE\WIN10\DLL Debug\Win32 +:: SET WOLFSSLJNI_DLL_DIR=..\..\IDE\WIN\DLL Debug\Win32 + +:: wolfSSL Normal non-FIPS (DLL Release Win32) +:: SET WOLFSSL_DLL_DIR=..\..\..\wolfssl\IDE\WIN10\DLL Release\Win32 +:: SET WOLFSSLJNI_DLL_DIR=..\..\IDE\WIN\DLL Release\Win32 + +:: wolfSSL FIPS 140-2 #3389 Build (DLL Debug x64) +:: SET WOLFSSL_DLL_DIR=..\..\..\wolfssl\IDE\WIN10\DLL Debug\x64 +:: SET WOLFSSLJNI_DLL_DIR=..\..\IDE\WIN\DLL Debug FIPS\x64 + +:: wolfSSL FIPS 140-2 #3389 Build (DLL Release x64) +:: SET WOLFSSL_DLL_DIR=..\..\..\wolfssl\IDE\WIN10\DLL Release\x64 +:: SET WOLFSSLJNI_DLL_DIR=..\..\IDE\WIN\DLL Release FIPS\x64 + +:: wolfSSL FIPS 140-2 #3389 Build (DLL Debug Win32) +:: SET WOLFSSL_DLL_DIR=..\..\..\wolfssl\IDE\WIN10\DLL Debug\Win32 +:: SET WOLFSSLJNI_DLL_DIR=..\..\IDE\WIN\DLL Debug FIPS\Win32 + +:: wolfSSL FIPS 140-2 #3389 Build (DLL Release Win32) +:: SET WOLFSSL_DLL_DIR=..\..\..\wolfssl\IDE\WIN10\DLL Release\Win32 +:: SET WOLFSSLJNI_DLL_DIR=..\..\IDE\WIN\DLL Release FIPS\Win32 + diff --git a/examples/X509v3CertificateGeneration.bat b/examples/X509v3CertificateGeneration.bat new file mode 100644 index 00000000..c2f59ee2 --- /dev/null +++ b/examples/X509v3CertificateGeneration.bat @@ -0,0 +1,14 @@ + +cd %~dp0\build >NUL 2>NUL +SETLOCAL + +:: Populate correct config for build +call ..\WindowsConfig.bat + +:: Set PATH to include DLL for native wolfSSL and wolfSSL JNI (native library) +SET PATH="%WOLFSSLJNI_DLL_DIR%;%WOLFSSL_DLL_DIR%";%PATH% + +java -cp ".;..\..\lib\wolfssl.jar;..\..\lib\wolfssl-jsse.jar" -Djava.library.path="%WOLFSSLJNI_DLL_DIR%;%WOLFSSL_DLL_DIR%" X509v3CertificateGeneration + +ENDLOCAL +cd %~dp0\.. diff --git a/examples/provider/ProviderTest.bat b/examples/provider/ProviderTest.bat new file mode 100644 index 00000000..b6dfd9d8 --- /dev/null +++ b/examples/provider/ProviderTest.bat @@ -0,0 +1,14 @@ + +cd %~dp0\..\build >NUL 2>NUL +SETLOCAL + +:: Populate correct config for build +call ..\WindowsConfig.bat + +:: Set PATH to include DLL for native wolfSSL and wolfSSL JNI (native library) +SET PATH="%WOLFSSLJNI_DLL_DIR%;%WOLFSSL_DLL_DIR%";%PATH% + +java -cp ".;..\..\lib\wolfssl.jar;..\..\lib\wolfssl-jsse.jar" -Djava.library.path="%WOLFSSLJNI_DLL_DIR%;%WOLFSSL_DLL_DIR%" ProviderTest + +ENDLOCAL +cd %~dp0\..\..