diff --git a/IDE/WIN/README.md b/IDE/WIN/README.md
index 33997b6..96a095b 100644
--- a/IDE/WIN/README.md
+++ b/IDE/WIN/README.md
@@ -419,9 +419,10 @@ to run the ProviderTest:
examples\provider\ProviderTest.bat
```
-Or to run the X509v3 certificate generation example:
+Or to run the X509v3 certificate or CSR generation example:
```
examples\X509v3CertificateGeneration.bat
+examples\X509CertRequest.bat
```
diff --git a/IDE/WIN/wolfssljni.vcxproj b/IDE/WIN/wolfssljni.vcxproj
index 68285ef..349e037 100644
--- a/IDE/WIN/wolfssljni.vcxproj
+++ b/IDE/WIN/wolfssljni.vcxproj
@@ -41,6 +41,7 @@
+
@@ -54,6 +55,7 @@
+
@@ -430,4 +432,4 @@ ant
-
\ No newline at end of file
+
diff --git a/IDE/WIN/wolfssljni.vcxproj.filters b/IDE/WIN/wolfssljni.vcxproj.filters
index c330006..a0b5143 100644
--- a/IDE/WIN/wolfssljni.vcxproj.filters
+++ b/IDE/WIN/wolfssljni.vcxproj.filters
@@ -33,6 +33,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -71,6 +74,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -84,4 +90,4 @@
Header Files
-
\ No newline at end of file
+
diff --git a/examples/README.md b/examples/README.md
index 6ab988d..8e9e0b3 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -63,6 +63,27 @@ This will write out generated certificates to the following directory:
examples/certs/generated/
```
+## Certificate Signing Request (CSR) Generation Example
+
+An example is included which will generate Certificate Signing Requests (CSR)
+using the wolfSSL JNI library `WolfSSLCertRequest` class.
+
+**X509CertRequest.java** - CSR 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/X509CertRequest.sh
+```
+
+This will write out generated CSRs to the following directory:
+
+```
+examples/certs/generated/
+```
+
## Support
Please contact the wolfSSL support team at support@wolfssl.com with any
diff --git a/examples/X509CertRequest.bat b/examples/X509CertRequest.bat
new file mode 100644
index 0000000..3a3d4e3
--- /dev/null
+++ b/examples/X509CertRequest.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%" X509CertRequest
+
+ENDLOCAL
+cd %~dp0\..
diff --git a/examples/X509CertRequest.java b/examples/X509CertRequest.java
new file mode 100644
index 0000000..6bc9ec6
--- /dev/null
+++ b/examples/X509CertRequest.java
@@ -0,0 +1,366 @@
+/* X509CertRequest.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.File;
+import java.io.IOException;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import java.security.PublicKey;
+import java.security.PrivateKey;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.cert.CertificateException;
+import java.security.NoSuchAlgorithmException;
+
+import com.wolfssl.WolfSSL;
+import com.wolfssl.WolfSSLCertRequest;
+import com.wolfssl.WolfSSLX509Name;
+import com.wolfssl.WolfSSLException;
+import com.wolfssl.WolfSSLJNIException;
+
+/**
+ * Example application that demonstrates X509 Certificate Signing Request (CSR)
+ * generation including various combinations.
+ *
+ * CSR using files as input for certs/keys
+ * CSR using arrays as input for certs/keys
+ * CSR 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 X509CertRequest {
+
+ 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 CSR gen example with files */
+ private static String clientKeyDer = CERT_DIR + "client-key.der";
+ private static String clientKeyPubDer = CERT_DIR + "client-keyPub.der";
+
+ /* Generated certificate signing request (CSR) locations. */
+ private static String csrUsingFilesDer =
+ GEN_DIR + "csr-using-files.der";
+ private static String csrUsingFilesPem =
+ GEN_DIR + "csr-using-files.pem";
+ private static String csrUsingArraysDer =
+ GEN_DIR + "csr-using-arrays.der";
+ private static String csrUsingArraysPem =
+ GEN_DIR + "csr-using-arrays.pem";
+ private static String csrUsingGeneratedKeysDer =
+ GEN_DIR + "csr-generated-keys.der";
+ private static String csrUsingGeneratedKeysPem =
+ GEN_DIR + "csr-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";
+
+ /* Example Attribute values */
+ private static String test_CHALLENGE_PASSWORD =
+ "12345!@#$%";
+
+ 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 Signing Request (CSR) using the following
+ * files as input to the CSR generation process:
+ *
+ * clientKeyPubDer - Existing client public key in DER format
+ * clientKeyDer - Existing client private key in DER format
+ *
+ * Generates and writes CSR out to the following paths in
+ * both PEM and DER format (see variable values above):
+ * csrUsingFilesDer (DER format)
+ * csrUsingFilesPem (PEM format)
+ *
+ * @throws WolfSSLException if error occurs during CSR generation process.
+ * @throws WolfSSLJNIException if native JNI error occurs
+ * @throws IOException on error writing to output file locations
+ */
+ public void generateCSRUsingFiles()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException {
+
+ System.out.print("\nGenerating CSR using files");
+
+ /* Create new CSR object */
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+
+ /* Set Subject Name */
+ WolfSSLX509Name subjectName = generateTestSubjectName();
+ req.setSubjectName(subjectName);
+
+ /* Set Public Key from existing public key DER file */
+ req.setPublicKey(clientKeyPubDer, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1);
+
+ /* Add Attributes */
+ req.addAttribute(WolfSSL.NID_pkcs9_challengePassword,
+ test_CHALLENGE_PASSWORD.getBytes());
+
+ /* Add Extensions */
+ req.addExtension(WolfSSL.NID_key_usage, test_KEY_USAGE, false);
+ req.addExtension(WolfSSL.NID_ext_key_usage, test_EXT_KEY_USAGE, false);
+ req.addExtension(WolfSSL.NID_subject_alt_name, test_ALT_NAME, false);
+ req.addExtension(WolfSSL.NID_basic_constraints, true, true);
+
+ /* Sign CSR, using existing client key DER */
+ req.signRequest(clientKeyDer, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1, "SHA256");
+
+ /* Output to DER and PEM files */
+ byte[] derCsr = req.getDer();
+ byte[] pemCsr = req.getPem();
+
+ /* Write out generated CSRs to files */
+ writeFile(csrUsingFilesDer, derCsr);
+ writeFile(csrUsingFilesPem, pemCsr);
+
+ System.out.println("... ");
+ System.out.println(" " + CERT_DIR_FROM_ROOT +
+ Paths.get(csrUsingFilesDer).getFileName());
+ System.out.println(" " + CERT_DIR_FROM_ROOT +
+ Paths.get(csrUsingFilesPem).getFileName());
+
+ /* Free native memory */
+ subjectName.free();
+ req.free();
+ }
+
+ /**
+ * Generate example Certificate Signing Request (CSR) using the following
+ * files in array format as input to the CSR generation process:
+ *
+ * clientKeyPubDer - Existing client public key in DER format
+ * clientKeyDer - Existing client private key in DER format
+ *
+ * Generates and writes CSR out to the following paths in
+ * both PEM and DER format (see variable values above):
+ * csrUsingArraysDer (DER format)
+ * csrUsingArraysPem (PEM format)
+ *
+ * @throws WolfSSLException if error occurs during CSR generation process.
+ * @throws WolfSSLJNIException if native JNI error occurs
+ * @throws IOException on error writing to output file locations
+ */
+ public void generateCSRUsingArrays()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException {
+
+ System.out.print("\nGenerating CSR using arrays");
+
+ /* Create new CSR object */
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+
+ /* Set Subject Name */
+ WolfSSLX509Name subjectName = generateTestSubjectName();
+ req.setSubjectName(subjectName);
+
+ /* Set Public Key from existing public key DER file */
+ byte[] pubKey = Files.readAllBytes(Paths.get(clientKeyPubDer));
+ req.setPublicKey(pubKey, WolfSSL.RSAk, WolfSSL.SSL_FILETYPE_ASN1);
+
+ /* Add Attributes */
+ req.addAttribute(WolfSSL.NID_pkcs9_challengePassword,
+ test_CHALLENGE_PASSWORD.getBytes());
+
+ /* Add Extensions */
+ req.addExtension(WolfSSL.NID_key_usage, test_KEY_USAGE, false);
+ req.addExtension(WolfSSL.NID_ext_key_usage, test_EXT_KEY_USAGE, false);
+ req.addExtension(WolfSSL.NID_subject_alt_name, test_ALT_NAME, false);
+ req.addExtension(WolfSSL.NID_basic_constraints, true, true);
+
+ /* Sign CSR, using existing client key DER */
+ byte[] privKey = Files.readAllBytes(Paths.get(clientKeyDer));
+ req.signRequest(privKey, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1, "SHA256");
+
+ /* Output to DER and PEM files */
+ byte[] derCsr = req.getDer();
+ byte[] pemCsr = req.getPem();
+
+ /* Write out generated CSRs to files */
+ writeFile(csrUsingArraysDer, derCsr);
+ writeFile(csrUsingArraysPem, pemCsr);
+
+ System.out.println("... ");
+ System.out.println(" " + CERT_DIR_FROM_ROOT +
+ Paths.get(csrUsingArraysDer).getFileName());
+ System.out.println(" " + CERT_DIR_FROM_ROOT +
+ Paths.get(csrUsingArraysPem).getFileName());
+
+ /* Free native memory */
+ subjectName.free();
+ req.free();
+ }
+
+ /**
+ * Generate example Certificate Signing Request (CSR) using generated keys
+ * for the CSR public and private signgin key, to be used in the CSR
+ * generation process.
+ *
+ * Generates and writes CSR out to the following paths in
+ * both PEM and DER format (see variable values above):
+ * csrUsingGeneratedKeysDer (DER format)
+ * csrUsingGeneratedKeysPem (PEM format)
+ *
+ * @throws WolfSSLException if error occurs during CSR generation process.
+ * @throws WolfSSLJNIException if native JNI error occurs
+ * @throws IOException on error writing to output file locations
+ */
+ public void generateCSRUsingGeneratedKeys()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException, NoSuchAlgorithmException {
+
+ System.out.print("\nGenerating CSR with generated keys");
+
+ /* Create new CSR object */
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+
+ /* Set Subject Name */
+ WolfSSLX509Name subjectName = generateTestSubjectName();
+ req.setSubjectName(subjectName);
+
+ /* Set Public Key from generated java.security.PublicKey */
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(2048);
+ KeyPair keyPair = kpg.generateKeyPair();
+ PublicKey pubKey = keyPair.getPublic();
+ req.setPublicKey(pubKey);
+
+ /* Add Attributes */
+ req.addAttribute(WolfSSL.NID_pkcs9_challengePassword,
+ test_CHALLENGE_PASSWORD.getBytes());
+
+ /* Add Extensions */
+ req.addExtension(WolfSSL.NID_key_usage, test_KEY_USAGE, false);
+ req.addExtension(WolfSSL.NID_ext_key_usage, test_EXT_KEY_USAGE, false);
+ req.addExtension(WolfSSL.NID_subject_alt_name, test_ALT_NAME, false);
+ req.addExtension(WolfSSL.NID_basic_constraints, true, true);
+
+ /* Sign CSR, with java.security.PrivateKey */
+ PrivateKey privKey = keyPair.getPrivate();
+ req.signRequest(privKey, "SHA256");
+
+ /* Output to DER and PEM files */
+ byte[] derCsr = req.getDer();
+ byte[] pemCsr = req.getPem();
+
+ /* Write out generated CSRs to files */
+ writeFile(csrUsingGeneratedKeysDer, derCsr);
+ writeFile(csrUsingGeneratedKeysPem, pemCsr);
+
+ System.out.println("... ");
+ System.out.println(" " + CERT_DIR_FROM_ROOT +
+ Paths.get(csrUsingGeneratedKeysDer).getFileName());
+ System.out.println(" " + CERT_DIR_FROM_ROOT +
+ Paths.get(csrUsingGeneratedKeysPem).getFileName());
+
+ /* Free native memory */
+ subjectName.free();
+ req.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 Certificate Signing Request Generation Example");
+
+ if (!WolfSSL.certReqEnabled()) {
+ System.out.println("ERROR: Native wolfSSL must be compiled " +
+ "with --enable-certreq or WOLFSSL_CERT_REQ to use this " +
+ "example");
+
+ /* exit with error */
+ System.exit(1);
+ }
+
+ /* Generate example Certificate Signing Request files */
+ generateCSRUsingFiles();
+ generateCSRUsingArrays();
+ generateCSRUsingGeneratedKeys();
+
+ } catch (WolfSSLException | WolfSSLJNIException |
+ IOException | CertificateException |
+ NoSuchAlgorithmException e) {
+ e.printStackTrace();
+
+ /* exit with error */
+ System.exit(1);
+ }
+
+ } /* end run() */
+
+ public static void main(String[] args) {
+ new X509CertRequest().run(args);
+ }
+
+} /* end X509CertRequest */
+
+
diff --git a/examples/X509CertRequest.sh b/examples/X509CertRequest.sh
new file mode 100755
index 0000000..b9865d3
--- /dev/null
+++ b/examples/X509CertRequest.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 X509CertRequest $@
+
+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 CSRs with openssl...\n"
+
+printf "Testing each can be opened with openssl req -text\n"
+
+# Test reading each DER CSR
+CERT_FILES="../certs/generated/csr*.der"
+for f in $CERT_FILES
+do
+ $OPENSSL req -inform DER -in $f -text -noout > /dev/null
+ if [ $? != 0 ]; then
+ printf "File not readable with openssl req: $f\n"
+ exit -1
+ fi
+done
+
+# Test reading each PEM CSR
+CERT_FILES="../certs/generated/csr*.pem"
+for f in $CERT_FILES
+do
+ $OPENSSL req -inform PEM -in $f -text -noout > /dev/null
+ if [ $? != 0 ]; then
+ printf "File not readable with openssl req: $f\n"
+ exit -1
+ fi
+done
+
+printf "Verification successful\n"
diff --git a/examples/certs/ecc-client-key.der b/examples/certs/ecc-client-key.der
new file mode 100644
index 0000000..0637390
Binary files /dev/null and b/examples/certs/ecc-client-key.der differ
diff --git a/examples/certs/update-certs.sh b/examples/certs/update-certs.sh
index c113aeb..3404765 100755
--- a/examples/certs/update-certs.sh
+++ b/examples/certs/update-certs.sh
@@ -41,6 +41,7 @@ certList=(
"client-key.der"
"client-keyPub.der"
"dh2048.pem"
+ "ecc-client-key.der"
"ecc-client-key.pem"
"ecc-key.pem"
"server-cert.pem"
diff --git a/java.sh b/java.sh
index cfbc258..3f2f4b4 100755
--- a/java.sh
+++ b/java.sh
@@ -115,10 +115,11 @@ gcc -Wall -c $fpic $cflags ./native/com_wolfssl_wolfcrypt_RSA.c -o ./native/com_
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_wolfcrypt_ECC.c -o ./native/com_wolfssl_wolfcrypt_ECC.o $javaIncludes
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_wolfcrypt_EccKey.c -o ./native/com_wolfssl_wolfcrypt_EccKey.o $javaIncludes
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLCertManager.c -o ./native/com_wolfssl_WolfSSLCertManager.o $javaIncludes
+gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLCertRequest.c -o ./native/com_wolfssl_WolfSSLCertRequest.o $javaIncludes
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLCertificate.c -o ./native/com_wolfssl_WolfSSLCertificate.o $javaIncludes
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLX509Name.c -o ./native/com_wolfssl_WolfSSLX509Name.o $javaIncludes
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLX509StoreCtx.c -o ./native/com_wolfssl_WolfSSLX509StoreCtx.o $javaIncludes
-gcc -Wall $javaLibs $cflags -o ./lib/$jniLibName ./native/com_wolfssl_WolfSSL.o ./native/com_wolfssl_WolfSSLSession.o ./native/com_wolfssl_WolfSSLContext.o ./native/com_wolfssl_wolfcrypt_RSA.o ./native/com_wolfssl_wolfcrypt_ECC.o ./native/com_wolfssl_wolfcrypt_EccKey.o ./native/com_wolfssl_WolfSSLCertManager.o ./native/com_wolfssl_WolfSSLCertificate.o ./native/com_wolfssl_WolfSSLX509Name.o ./native/com_wolfssl_WolfSSLX509StoreCtx.o -L$WOLFSSL_INSTALL_DIR/lib -L$WOLFSSL_INSTALL_DIR/lib64 -l$WOLFSSL_LIBNAME
+gcc -Wall $javaLibs $cflags -o ./lib/$jniLibName ./native/com_wolfssl_WolfSSL.o ./native/com_wolfssl_WolfSSLSession.o ./native/com_wolfssl_WolfSSLContext.o ./native/com_wolfssl_wolfcrypt_RSA.o ./native/com_wolfssl_wolfcrypt_ECC.o ./native/com_wolfssl_wolfcrypt_EccKey.o ./native/com_wolfssl_WolfSSLCertManager.o ./native/com_wolfssl_WolfSSLCertRequest.o ./native/com_wolfssl_WolfSSLCertificate.o ./native/com_wolfssl_WolfSSLX509Name.o ./native/com_wolfssl_WolfSSLX509StoreCtx.o -L$WOLFSSL_INSTALL_DIR/lib -L$WOLFSSL_INSTALL_DIR/lib64 -l$WOLFSSL_LIBNAME
if [ $? != 0 ]; then
echo "Error creating native JNI library"
exit 1
diff --git a/native/com_wolfssl_WolfSSL.c b/native/com_wolfssl_WolfSSL.c
index 3d315a2..15d31f0 100644
--- a/native/com_wolfssl_WolfSSL.c
+++ b/native/com_wolfssl_WolfSSL.c
@@ -386,6 +386,19 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_FileSystemEnabled
#endif
}
+JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_certReqEnabled
+ (JNIEnv* jenv, jclass jcl)
+{
+ (void)jenv;
+ (void)jcl;
+
+#ifdef WOLFSSL_CERT_REQ
+ return JNI_TRUE;
+#else
+ return JNI_FALSE;
+#endif
+}
+
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_SSLv3_1ServerMethod
(JNIEnv* jenv, jclass jcl)
{
diff --git a/native/com_wolfssl_WolfSSL.h b/native/com_wolfssl_WolfSSL.h
index c4b71e3..b68a573 100644
--- a/native/com_wolfssl_WolfSSL.h
+++ b/native/com_wolfssl_WolfSSL.h
@@ -211,6 +211,20 @@ extern "C" {
#define com_wolfssl_WolfSSL_ASN_URI_TYPE 6L
#undef com_wolfssl_WolfSSL_ASN_IP_TYPE
#define com_wolfssl_WolfSSL_ASN_IP_TYPE 7L
+#undef com_wolfssl_WolfSSL_NID_surname
+#define com_wolfssl_WolfSSL_NID_surname 4L
+#undef com_wolfssl_WolfSSL_NID_serialNumber
+#define com_wolfssl_WolfSSL_NID_serialNumber 5L
+#undef com_wolfssl_WolfSSL_NID_pkcs9_unstructuredName
+#define com_wolfssl_WolfSSL_NID_pkcs9_unstructuredName 49L
+#undef com_wolfssl_WolfSSL_NID_pkcs9_contentType
+#define com_wolfssl_WolfSSL_NID_pkcs9_contentType 50L
+#undef com_wolfssl_WolfSSL_NID_pkcs9_challengePassword
+#define com_wolfssl_WolfSSL_NID_pkcs9_challengePassword 54L
+#undef com_wolfssl_WolfSSL_NID_givenName
+#define com_wolfssl_WolfSSL_NID_givenName 100L
+#undef com_wolfssl_WolfSSL_NID_initials
+#define com_wolfssl_WolfSSL_NID_initials 101L
#undef com_wolfssl_WolfSSL_NID_key_usage
#define com_wolfssl_WolfSSL_NID_key_usage 129L
#undef com_wolfssl_WolfSSL_NID_subject_alt_name
@@ -219,6 +233,8 @@ extern "C" {
#define com_wolfssl_WolfSSL_NID_basic_constraints 133L
#undef com_wolfssl_WolfSSL_NID_ext_key_usage
#define com_wolfssl_WolfSSL_NID_ext_key_usage 151L
+#undef com_wolfssl_WolfSSL_NID_dnQualifier
+#define com_wolfssl_WolfSSL_NID_dnQualifier 174L
#undef com_wolfssl_WolfSSL_WOLFSSL_NAMED_GROUP_INVALID
#define com_wolfssl_WolfSSL_WOLFSSL_NAMED_GROUP_INVALID 0L
#undef com_wolfssl_WolfSSL_WOLFSSL_ECC_SECT163K1
@@ -477,6 +493,14 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_RsaEnabled
JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_FileSystemEnabled
(JNIEnv *, jclass);
+/*
+ * Class: com_wolfssl_WolfSSL
+ * Method: certReqEnabled
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_certReqEnabled
+ (JNIEnv *, jclass);
+
/*
* Class: com_wolfssl_WolfSSL
* Method: SSLv3_ServerMethod
diff --git a/native/com_wolfssl_WolfSSLCertRequest.c b/native/com_wolfssl_WolfSSLCertRequest.c
new file mode 100644
index 0000000..14d515f
--- /dev/null
+++ b/native/com_wolfssl_WolfSSLCertRequest.c
@@ -0,0 +1,728 @@
+/* com_wolfssl_WolfSSLCertRequest.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
+#include
+#include
+#include /* for EVP_PKEY functions */
+#include /* for WOLFSSL_X509_EXTENSION */
+#include
+
+#include "com_wolfssl_globals.h"
+#include "com_wolfssl_WolfSSLCertRequest.h"
+
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1new
+ (JNIEnv* jenv, jclass jcl)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_ALL) && \
+ defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ)
+ WOLFSSL_X509* x509 = NULL;
+ (void)jcl;
+
+ if (jenv == NULL) {
+ return (jlong)0;
+ }
+
+ x509 = wolfSSL_X509_REQ_new();
+ if (x509 == NULL) {
+ return (jlong)0;
+ }
+
+ return (jlong)(uintptr_t)x509;
+#else
+ (void)jenv;
+ (void)jcl;
+ return (jlong)0;
+#endif
+}
+
+JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1free
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_ALL) && \
+ defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ)
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ (void)jcl;
+
+ if (jenv == NULL || x509 == NULL) {
+ return;
+ }
+
+ wolfSSL_X509_REQ_free(x509);
+#else
+ (void)jenv;
+ (void)jcl;
+ return;
+#endif
+}
+
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1set_1subject_1name
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr, jlong x509NamePtr)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_ALL) && \
+ defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ)
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ WOLFSSL_X509_NAME* x509Name = (WOLFSSL_X509_NAME*)(uintptr_t)x509NamePtr;
+ int ret = WOLFSSL_FAILURE;
+ (void)jcl;
+
+ if (jenv == NULL || x509 == NULL || x509Name == NULL) {
+ return ret;
+ }
+
+ ret = wolfSSL_X509_REQ_set_subject_name(x509, x509Name);
+
+ return ret;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)x509ReqPtr;
+ (void)x509NamePtr;
+ return (jint)NOT_COMPILED_IN;
+#endif
+}
+
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1add1_1attr_1by_1NID
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr, jint nid, jint type, jbyteArray attrBytes)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_ALL) && \
+ defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ)
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ int ret = WOLFSSL_SUCCESS;
+ unsigned char* attr = NULL;
+ int attrSz = 0;
+ (void)jcl;
+
+ if (jenv == NULL || x509 == NULL || attrBytes == NULL) {
+ return WOLFSSL_FAILURE;
+ }
+
+ attr = (byte*)(*jenv)->GetByteArrayElements(jenv, attrBytes, NULL);
+ attrSz = (*jenv)->GetArrayLength(jenv, attrBytes);
+
+ if (attr == NULL || attrSz <= 0) {
+ ret = WOLFSSL_FAILURE;
+ }
+
+ if (ret == WOLFSSL_SUCCESS) {
+ ret = X509_REQ_add1_attr_by_NID(x509, (int)nid, (int)type,
+ attr, attrSz);
+ }
+
+ (*jenv)->ReleaseByteArrayElements(jenv, attrBytes, (jbyte*)attr, JNI_ABORT);
+
+ return (jint)ret;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)x509ReqPtr;
+ (void)nid;
+ (void)type;
+ (void)attrBytes;
+ return (jint)NOT_COMPILED_IN;
+#endif
+}
+
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1set_1version
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr, jlong version)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \
+ (defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ int ret = WOLFSSL_SUCCESS;
+ (void)jcl;
+
+ if (jenv == NULL || x509 == NULL) {
+ return WOLFSSL_FAILURE;
+ }
+
+ ret = X509_REQ_set_version(x509, (long)version);
+
+ return (jint)ret;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)x509ReqPtr;
+ (void)version;
+ return (jint)NOT_COMPILED_IN;
+#endif
+}
+
+JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1print
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && \
+ defined(OPENSSL_EXTRA) && !defined(NO_BIO) && defined(XSNPRINTF) && \
+ defined(WOLFSSL_CERT_REQ)
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ WOLFSSL_BIO* bio = NULL;
+ char* mem = NULL;
+ int sz = 0;
+ jbyteArray memArr = NULL;
+ (void)jcl;
+
+ if (jenv == NULL || x509 == NULL) {
+ return NULL;
+ }
+
+ bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem());
+ if (bio == NULL) {
+ return NULL;
+ }
+
+ if (wolfSSL_X509_REQ_print(bio, x509) != WOLFSSL_SUCCESS) {
+ wolfSSL_BIO_free(bio);
+ return NULL;
+ }
+
+ sz = wolfSSL_BIO_get_mem_data(bio, &mem);
+ if (sz > 0 && mem != NULL) {
+
+ memArr = (*jenv)->NewByteArray(jenv, sz);
+ if (memArr == NULL) {
+ wolfSSL_BIO_free(bio);
+ return NULL;
+ }
+
+ (*jenv)->SetByteArrayRegion(jenv, memArr, 0, sz, (jbyte*)mem);
+ if ((*jenv)->ExceptionOccurred(jenv)) {
+ /* failed to set byte region */
+ (*jenv)->DeleteLocalRef(jenv, memArr);
+ wolfSSL_BIO_free(bio);
+ return NULL;
+ }
+ }
+ wolfSSL_BIO_free(bio);
+ return memArr;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)x509ReqPtr;
+ return NULL;
+#endif
+}
+
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1sign
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr, jint keyType, jbyteArray keyBytes, jint fileFormat, jstring digestAlg)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_ALL) && \
+ defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ)
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ byte* keyBuf = NULL;
+ byte* derBuf = NULL;
+ int keySz = 0;
+ 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;
+ }
+
+ keyBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, keyBytes, NULL);
+ keySz = (*jenv)->GetArrayLength(jenv, keyBytes);
+
+ if (keyBuf == NULL || keySz == 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 = keyBuf;
+ derSz = keySz;
+ }
+ else {
+ /* get needed buffer size */
+ ret = wc_KeyPemToDer(keyBuf, keySz, 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(keyBuf, keySz, 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;
+ }
+ }
+
+ /* sign WOLFSSL_X509 with WOLFSSL_EVP_PKEY, returns size of signature
+ * on success or negative on error */
+ if (ret == WOLFSSL_SUCCESS) {
+ ret = wolfSSL_X509_REQ_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, keyBytes, (jbyte*)keyBuf,
+ JNI_ABORT);
+ (*jenv)->ReleaseStringUTFChars(jenv, digestAlg, mdName);
+
+ return (jint)ret;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)x509ReqPtr;
+ (void)keyType;
+ (void)keyBytes;
+ (void)fileFormat;
+ (void)digestAlg;
+ return (jint)NOT_COMPILED_IN;
+#endif
+}
+
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1set_1pubkey_1native_1open
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr, 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)x509ReqPtr;
+ byte* fileBuf = NULL;
+ byte* derBuf = NULL;
+ int fileSz = 0;
+ 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)x509ReqPtr;
+ (void)keyType;
+ (void)fileBytes;
+ (void)fileFormat;
+ return (jint)NOT_COMPILED_IN;
+#endif
+}
+
+JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1get_1der
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_ALL) && \
+ defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \
+ !defined(NO_BIO)
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ unsigned char* der = NULL;
+ jbyteArray derArr = NULL;
+ jclass excClass = NULL;
+ int sz = 0;
+ (void)jcl;
+
+ if (jenv == NULL || x509 == NULL) {
+ return NULL;
+ }
+
+ sz = wolfSSL_i2d_X509_REQ(x509, &der);
+ if (sz <= 0) {
+ return NULL;
+ }
+
+ derArr = (*jenv)->NewByteArray(jenv, sz);
+ if (derArr == NULL) {
+ (*jenv)->ThrowNew(jenv, jcl,
+ "Failed to create byte array in native X509_REQ_get_der");
+ return NULL;
+ }
+
+ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException");
+ if ((*jenv)->ExceptionOccurred(jenv)) {
+ (*jenv)->ExceptionDescribe(jenv);
+ (*jenv)->ExceptionClear(jenv);
+ (*jenv)->DeleteLocalRef(jenv, derArr);
+ XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
+ return NULL;
+ }
+
+ (*jenv)->SetByteArrayRegion(jenv, derArr, 0, sz, (jbyte*)der);
+ if ((*jenv)->ExceptionOccurred(jenv)) {
+ (*jenv)->ExceptionDescribe(jenv);
+ (*jenv)->ExceptionClear(jenv);
+ (*jenv)->DeleteLocalRef(jenv, derArr);
+ XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
+ (*jenv)->ThrowNew(jenv, excClass,
+ "Failed to set byte region in native X509_REQ_get_der");
+ return NULL;
+ }
+
+ XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
+
+ return derArr;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)x509ReqPtr;
+ return NULL;
+#endif
+}
+
+JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1get_1pem
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_ALL) && \
+ defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_REQ) && \
+ !defined(NO_BIO)
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ unsigned char* der = NULL;
+ unsigned char* pem = NULL;
+ int sz = 0;
+ int pemSz = 0;
+ jbyteArray pemArr = NULL;
+ jclass excClass = NULL;
+ (void)jcl;
+
+ if (jenv == NULL || x509 == NULL) {
+ return NULL;
+ }
+
+ sz = wolfSSL_i2d_X509_REQ(x509, &der);
+ if (sz <= 0) {
+ return NULL;
+ }
+
+ pemSz = wc_DerToPem(der, sz, NULL, 0, CERTREQ_TYPE);
+ if (pemSz < 0) {
+ XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
+ return NULL;
+ }
+
+ pem = (byte*)XMALLOC(pemSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ if (pem == NULL) {
+ XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
+ return NULL;
+ }
+ XMEMSET(pem, 0, pemSz);
+
+ pemSz = wc_DerToPem(der, sz, pem, pemSz, CERTREQ_TYPE);
+ if (pemSz < 0) {
+ XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
+ XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ return NULL;
+ }
+ XFREE(der, NULL, DYNAMIC_TYPE_OPENSSL);
+
+ pemArr = (*jenv)->NewByteArray(jenv, pemSz);
+ if (pemArr == NULL) {
+ (*jenv)->ThrowNew(jenv, jcl,
+ "Failed to create byte array in native X509_REQ_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);
+ XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+ (*jenv)->ThrowNew(jenv, excClass,
+ "Failed to set byte region in native X509_get_pem");
+ return NULL;
+ }
+
+ XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+
+ return pemArr;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)x509ReqPtr;
+ return NULL;
+#endif
+}
+
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1nconf_1nid
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr, jint nid, jstring extValue, jboolean isCritical)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA)
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ 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)x509ReqPtr;
+ (void)nid;
+ (void)extValue;
+ (void)isCritical;
+ return (jint)NOT_COMPILED_IN;
+#endif
+}
+
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1set_1object_1boolean
+ (JNIEnv* jenv, jclass jcl, jlong x509ReqPtr, jint nid, jboolean extValue, jboolean isCritical)
+{
+#if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS) && defined(OPENSSL_EXTRA)
+ WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509ReqPtr;
+ 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)x509ReqPtr;
+ (void)nid;
+ (void)extValue;
+ (void)isCritical;
+ return (jint)NOT_COMPILED_IN;
+#endif
+}
+
diff --git a/native/com_wolfssl_WolfSSLCertRequest.h b/native/com_wolfssl_WolfSSLCertRequest.h
new file mode 100644
index 0000000..88900c7
--- /dev/null
+++ b/native/com_wolfssl_WolfSSLCertRequest.h
@@ -0,0 +1,115 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include
+/* Header for class com_wolfssl_WolfSSLCertRequest */
+
+#ifndef _Included_com_wolfssl_WolfSSLCertRequest
+#define _Included_com_wolfssl_WolfSSLCertRequest
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef com_wolfssl_WolfSSLCertRequest_EVP_PKEY_RSA
+#define com_wolfssl_WolfSSLCertRequest_EVP_PKEY_RSA 16L
+#undef com_wolfssl_WolfSSLCertRequest_EVP_PKEY_EC
+#define com_wolfssl_WolfSSLCertRequest_EVP_PKEY_EC 18L
+#undef com_wolfssl_WolfSSLCertRequest_MBSTRING_ASC
+#define com_wolfssl_WolfSSLCertRequest_MBSTRING_ASC 4097L
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_new
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1new
+ (JNIEnv *, jclass);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_free
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1free
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_set_subject_name
+ * Signature: (JJ)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1set_1subject_1name
+ (JNIEnv *, jclass, jlong, jlong);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_add1_attr_by_NID
+ * Signature: (JII[B)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1add1_1attr_1by_1NID
+ (JNIEnv *, jclass, jlong, jint, jint, jbyteArray);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_set_version
+ * Signature: (JJ)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1set_1version
+ (JNIEnv *, jclass, jlong, jlong);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_print
+ * Signature: (J)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1print
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_sign
+ * Signature: (JI[BILjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1sign
+ (JNIEnv *, jclass, jlong, jint, jbyteArray, jint, jstring);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_set_pubkey_native_open
+ * Signature: (JI[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1set_1pubkey_1native_1open
+ (JNIEnv *, jclass, jlong, jint, jbyteArray, jint);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_get_der
+ * Signature: (J)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1get_1der
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_REQ_get_pem
+ * Signature: (J)[B
+ */
+JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1REQ_1get_1pem
+ (JNIEnv *, jclass, jlong);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_add_ext_via_nconf_nid
+ * Signature: (JILjava/lang/String;Z)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1nconf_1nid
+ (JNIEnv *, jclass, jlong, jint, jstring, jboolean);
+
+/*
+ * Class: com_wolfssl_WolfSSLCertRequest
+ * Method: X509_add_ext_via_set_object_boolean
+ * Signature: (JIZZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLCertRequest_X509_1add_1ext_1via_1set_1object_1boolean
+ (JNIEnv *, jclass, jlong, jint, jboolean, jboolean);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/java/com/wolfssl/WolfSSL.java b/src/java/com/wolfssl/WolfSSL.java
index 5b1fca2..d16b284 100644
--- a/src/java/com/wolfssl/WolfSSL.java
+++ b/src/java/com/wolfssl/WolfSSL.java
@@ -361,14 +361,30 @@ public class WolfSSL {
public static final int ASN_IP_TYPE = 0x07;
/* NIDs, from native asn.h */
+ /** Surname NID */
+ public static final int NID_surname = 4;
+ /** Serial number NID */
+ public static final int NID_serialNumber = 5;
+ /** PKCS9 Unstructured name NID */
+ public static final int NID_pkcs9_unstructuredName = 49;
+ /** PKCS9 contentType NID */
+ public static final int NID_pkcs9_contentType = 50;
+ /** PKCS9 challenge password NID */
+ public static final int NID_pkcs9_challengePassword = 54;
+ /** Given name NID */
+ public static final int NID_givenName = 100;
+ /** Initials NID */
+ public static final int NID_initials = 101;
/** Key Usage NID */
- public static final int NID_key_usage = 129;
+ public static final int NID_key_usage = 129;
/** Subject Alternative Name NID */
- public static final int NID_subject_alt_name = 131;
+ public static final int NID_subject_alt_name = 131;
/** Basic Constraints NID */
- public static final int NID_basic_constraints = 133;
+ public static final int NID_basic_constraints = 133;
/** Extended Key Usage NID */
- public static final int NID_ext_key_usage = 151;
+ public static final int NID_ext_key_usage = 151;
+ /** Domain name qualifier NID */
+ public static final int NID_dnQualifier = 174;
/* is this object active, or has it been cleaned up? */
private boolean active = false;
@@ -590,52 +606,61 @@ public class WolfSSL {
* TLS 1.0 is disabled by default in native wolfSSL, unless the user
* has configured wolfSSL with "--enable-tls10".
*
- * @return 1 if enabled, otherwise 0 if not compiled in.
+ * @return true if enabled, otherwise false if not compiled in.
*/
public static native boolean TLSv1Enabled();
/**
* Tests if TLS 1.1 has been compiled into the native wolfSSL library.
*
- * @return 1 if enabled, otherwise 0 if not compiled in.
+ * @return true if enabled, otherwise false if not compiled in.
*/
public static native boolean TLSv11Enabled();
/**
* Tests if TLS 1.2 has been compiled into the native wolfSSL library.
*
- * @return 1 if enabled, otherwise 0 if not compiled in.
+ * @return true if enabled, otherwise false if not compiled in.
*/
public static native boolean TLSv12Enabled();
/**
* Tests if TLS 1.3 has been compiled into the native wolfSSL library.
*
- * @return 1 if enabled, otherwise 0 if not compiled in.
+ * @return true if enabled, otherwise false if not compiled in.
*/
public static native boolean TLSv13Enabled();
/**
* Tests if ECC support has been compiled into the native wolfSSL library.
*
- * @return 1 if enabled, otherwise 0 if not compiled in.
+ * @return true if enabled, otherwise false if not compiled in.
*/
public static native boolean EccEnabled();
/**
* Tests if RSA support has been compiled into the native wolfSSL library.
*
- * @return 1 if enabled, otherwise 0 if not compiled in.
+ * @return true if enabled, otherwise false if not compiled in.
*/
public static native boolean RsaEnabled();
/**
* Tests if filesystem support has been compiled into the wolfSSL library.
*
- * @return 1 if enabled, otherwise 0 if NO_FILESYSTEM has been defined.
+ * @return true if enabled, otherwise false if NO_FILESYSTEM has been
+ * defined.
*/
public static native boolean FileSystemEnabled();
+ /**
+ * Tests if Certificate Signing Request (CSR) support has been compiled
+ * into the native wolfSSL library.
+ *
+ * @return true if enabled, otherwise false if WOLFSSL_CERT_EXT not defined.
+ */
+ public static native boolean certReqEnabled();
+
/* ---------------- native SSL/TLS version functions ---------------- */
/**
diff --git a/src/java/com/wolfssl/WolfSSLCertRequest.java b/src/java/com/wolfssl/WolfSSLCertRequest.java
new file mode 100644
index 0000000..78093d8
--- /dev/null
+++ b/src/java/com/wolfssl/WolfSSLCertRequest.java
@@ -0,0 +1,730 @@
+/* WolfSSLCertRequest.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;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.charset.Charset;
+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;
+
+/**
+ * WolfSSLCertRequest class, wraps native X509_REQ functionality.
+ */
+public class WolfSSLCertRequest {
+
+ private boolean active = false;
+
+ /* native X509_REQ pointer */
+ private long x509ReqPtr = 0;
+
+ /* lock around active state */
+ private final Object stateLock = new Object();
+
+ /* lock around native X509_REQ pointer use */
+ private final Object x509ReqLock = new Object();
+
+ /* Public key types used for CSR, 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;
+
+ /* Define from */
+ private static final int MBSTRING_ASC = 0x1001;
+
+ /* Native JNI methods */
+ static native long X509_REQ_new();
+ static native void X509_REQ_free(long x509ReqPtr);
+ static native int X509_REQ_set_subject_name(long x509ReqPtr,
+ long x509NamePtr);
+ static native int X509_REQ_add1_attr_by_NID(long x509ReqPtr, int nid,
+ int type, byte[] bytes);
+ static native int X509_REQ_set_version(long x509ReqPtr, long ver);
+ static native byte[] X509_REQ_print(long x509ReqPtr);
+ static native int X509_REQ_sign(long x509ReqPtr, int evpKeyType,
+ byte[] keyBytes, int format, String digestAlg);
+ static native int X509_REQ_set_pubkey_native_open(long x509ReqPtr,
+ int keyType, byte[] fileBytes, int format);
+ static native byte[] X509_REQ_get_der(long x509);
+ static native byte[] X509_REQ_get_pem(long x509);
+ 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);
+
+ /**
+ * Create new empty WolfSSLCertRequest object, for use with CSR generation
+ *
+ * @throws WolfSSLException if native API call fails.
+ */
+ public WolfSSLCertRequest() throws WolfSSLException {
+
+ x509ReqPtr = X509_REQ_new();
+ if (x509ReqPtr == 0) {
+ throw new WolfSSLException("Failed to create WolfSSLCertRequest");
+ }
+
+ synchronized (stateLock) {
+ this.active = true;
+ }
+ }
+
+ /**
+ * Verifies that the current WolfSSLCertRequest object is active.
+ *
+ * @throws IllegalStateException if object has been freed
+ */
+ private void confirmObjectIsActive()
+ throws IllegalStateException {
+
+ synchronized (stateLock) {
+ if (this.active == false) {
+ throw new IllegalStateException(
+ "WolfSSLCertRequest object has been freed");
+ }
+ }
+ }
+
+ /**
+ * Set the Subject Name to be used with this WolfSSLCertRequest.
+ * 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
+ * Subject Name of WolfSSLCertRequest for cert generation.
+ *
+ * @throws IllegalStateException if WolfSSLCertRequest has been freed.
+ * @throws WolfSSLException if native JNI error occurs.
+ */
+ public void setSubjectName(WolfSSLX509Name name)
+ throws IllegalStateException, WolfSSLException {
+
+ int ret;
+
+ confirmObjectIsActive();
+
+ synchronized (x509ReqLock) {
+ /* TODO somehow lock WolfSSLX509Name object while using pointer? */
+ ret = X509_REQ_set_subject_name(this.x509ReqPtr,
+ name.getNativeX509NamePtr());
+ }
+
+ if (ret != WolfSSL.SSL_SUCCESS) {
+ throw new WolfSSLException("Error setting subject name " +
+ "(ret: " + ret + ")");
+ }
+ }
+
+ /**
+ * Add a CSR attribute to this WolfSSLCertRequest
+ *
+ * @param nid NID of an attribute to add. Must be one of:
+ * WolfSSL.NID_pkcs9_challengePassword
+ * WolfSSL.NID_serialNumber
+ * WolfSSL.NID_pkcs9_unstructuredName
+ * WolfSSL.NID_pkcs9_contentType
+ * WolfSSL.NID_surname
+ * WolfSSL.NID_initials
+ * WolfSSL.NID_givenName
+ * WolfSSL.NID_dnQualifier
+ * @param value value of attribute to set, if passing in String, use
+ * String.getBytes()
+ *
+ * @throws IllegalStateException if WolfSSLCertRequest has been freed.
+ * @throws WolfSSLException if native JNI error occurs.
+ */
+ public void addAttribute(int nid, byte[] value)
+ throws IllegalStateException, WolfSSLException {
+
+ int ret;
+
+ confirmObjectIsActive();
+
+ if (nid != WolfSSL.NID_pkcs9_challengePassword &&
+ nid != WolfSSL.NID_serialNumber &&
+ nid != WolfSSL.NID_pkcs9_unstructuredName &&
+ nid != WolfSSL.NID_pkcs9_contentType &&
+ nid != WolfSSL.NID_surname &&
+ nid != WolfSSL.NID_initials &&
+ nid != WolfSSL.NID_givenName &&
+ nid != WolfSSL.NID_dnQualifier) {
+ throw new WolfSSLException(
+ "Unsupported CSR attribute NID: " + nid);
+ }
+
+ if (value == null || value.length == 0) {
+ throw new WolfSSLException(
+ "CSR attribute value may not be null or zero length");
+ }
+
+ synchronized (x509ReqLock) {
+ ret = X509_REQ_add1_attr_by_NID(this.x509ReqPtr, nid,
+ MBSTRING_ASC, value);
+ }
+
+ if (ret != WolfSSL.SSL_SUCCESS) {
+ throw new WolfSSLException("Error setting CSR attribute " +
+ "(ret: " + ret + ")");
+ }
+ }
+
+ /**
+ * Set CSR version for this WolfSSLCertRequest object.
+ *
+ * Calling this method is optional when generating a CSR. By default,
+ * a value of 0 (zero) is used for the CSR version. This is currently
+ * the version used by all CSR RFCs/specs.
+ *
+ * @param version version to set for CSR
+ *
+ * @throws IllegalStateException if WolfSSLCertRequest has been freed.
+ * @throws WolfSSLException if native JNI error occurs.
+ */
+ public void setVersion(long version)
+ throws IllegalStateException, WolfSSLException {
+
+ int ret;
+
+ confirmObjectIsActive();
+
+ synchronized (x509ReqLock) {
+ ret = X509_REQ_set_version(this.x509ReqPtr, version);
+ }
+
+ if (ret != WolfSSL.SSL_SUCCESS) {
+ throw new WolfSSLException("Error setting CSR version " +
+ "(ret: " + ret + ")");
+ }
+ }
+
+ /**
+ * Set public key for this WolfSSLCertRequest, used when generating
+ * Certificate Signing Requests
+ *
+ * @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 WolfSSLCertRequest 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 WolfSSLCertRequest, used when generating
+ * Certificate Signing Requests
+ *
+ * @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 WolfSSLCertRequest 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 (x509ReqLock) {
+ ret = X509_REQ_set_pubkey_native_open(this.x509ReqPtr, evpKeyType,
+ key, format);
+ }
+
+ if (ret != WolfSSL.SSL_SUCCESS) {
+ throw new WolfSSLException(
+ "Error setting public key into native WOLFSSL_X509_REQ " +
+ "(ret: " + ret + ")");
+ }
+ }
+
+ /**
+ * Set public key for this WolfSSLCertRequest, used when generating
+ * Certificate Signing Requests
+ *
+ * @param key PublicKey object containing public key to be used when
+ * generating CSR.
+ *
+ * @throws IllegalStateException if WolfSSLCertRequest 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);
+ }
+
+ /**
+ * Add an extension to a WolfSSLCertRequest 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_ext_key_usage
+ * WolfSSL.NID_subject_alt_name
+ * @param value String value of extension to set. For keyUsage and
+ * extKeyUsage this should be a comma-delimited list.
+ * For subjectAltName, this is a single value. Possible
+ * values for keyUsage and extKeyUsage are:
+ *
+ * NID_key_usage:
+ * digitalSignature
+ * nonRepudiation
+ * contentCommitment
+ * keyEncipherment
+ * dataEncipherment
+ * keyAgreement
+ * keyCertSign
+ * cRLSign
+ * encipherOnly
+ * decipherOnly
+ *
+ * NID_ext_key_usage:
+ * serverAuth
+ * clientAuth
+ * codeSigning
+ * emailProtection
+ * timeStamping
+ * OCSPSigning
+ *
+ * @param isCritical Boolean flag indicating if this extension is
+ * critical
+ *
+ * @throws IllegalStateException if WolfSSLCertRequest 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 (x509ReqLock) {
+ ret = X509_add_ext_via_nconf_nid(this.x509ReqPtr, 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 + ")");
+ }
+ }
+
+ /**
+ * Add an extension to a WolfSSLCertRequest 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_basic_constraints
+ * @param value Boolean value of extension (true/false)
+ * @param isCritical Boolean flag indicating if this extension is
+ * critical
+ *
+ * @throws IllegalStateException if WolfSSLCertRequest 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 (x509ReqLock) {
+ ret = X509_add_ext_via_set_object_boolean(
+ this.x509ReqPtr, nid, value, isCritical);
+ }
+
+ if (ret != WolfSSL.SSL_SUCCESS) {
+ throw new WolfSSLException(
+ "Error setting extension into native WOLFSSL_X509 " +
+ "(ret: " + ret + ")");
+ }
+ }
+
+ /**
+ * Sign certificate request 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 WolfSSLCertRequest has been freed.
+ * @throws IOException on error opening input file
+ * @throws WolfSSLException if invalid arguments or native JNI error occurs.
+ */
+ public void signRequest(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);
+ }
+
+ signRequest(Files.readAllBytes(keyFile.toPath()), keyType,
+ format, digestAlg);
+ }
+
+ /**
+ * Sign certificate request 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 WolfSSLCertRequest has been freed.
+ * @throws WolfSSLException if invalid arguments or native JNI error occurs.
+ */
+ public void signRequest(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 (x509ReqLock) {
+ ret = X509_REQ_sign(this.x509ReqPtr, evpKeyType, key, format,
+ digestAlg);
+ }
+
+ if (ret != WolfSSL.SSL_SUCCESS) {
+ throw new WolfSSLException(
+ "Error signing native X509_REQ " +
+ "(ret: " + ret + ")");
+ }
+ }
+
+ /**
+ * Sign certificate request 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 WolfSSLCertRequest has been freed.
+ * @throws WolfSSLException if invalid arguments or native JNI error occurs.
+ */
+ public void signRequest(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 (x509ReqLock) {
+ ret = X509_REQ_sign(this.x509ReqPtr, evpKeyType, encodedKey,
+ WolfSSL.SSL_FILETYPE_ASN1, digestAlg);
+ }
+
+ if (ret != WolfSSL.SSL_SUCCESS) {
+ throw new WolfSSLException(
+ "Error signing native X509_REQ " +
+ "(ret: " + ret + ")");
+ }
+ }
+
+ /**
+ * Get ASN.1/DER encoding of this CSR, after signRequest() has been called.
+ *
+ * @return DER encoded array of CSR or null if not available.
+ *
+ * @throws IllegalStateException if WolfSSLCertRequest has been freed.
+ * @throws WolfSSLJNIException if native JNI operation fails
+ */
+ public byte[] getDer() throws IllegalStateException, WolfSSLJNIException {
+
+ confirmObjectIsActive();
+
+ synchronized (x509ReqLock) {
+ return X509_REQ_get_der(this.x509ReqPtr);
+ }
+ }
+
+ /**
+ * Get PEM encoding of this CSR, after signRequest() has been called.
+ *
+ * @return PEM encoded array of CSR or null if not available.
+ *
+ * @throws IllegalStateException if WolfSSLCertRequest has been freed.
+ * @throws WolfSSLJNIException if native JNI operation fails
+ */
+ public byte[] getPem() throws IllegalStateException, WolfSSLJNIException {
+
+ confirmObjectIsActive();
+
+ synchronized (x509ReqLock) {
+ return X509_REQ_get_pem(this.x509ReqPtr);
+ }
+ }
+
+ @Override
+ public String toString() {
+
+ byte[] x509ReqText = null;
+
+ synchronized (stateLock) {
+ if (this.active == false) {
+ return super.toString();
+ }
+
+ synchronized (x509ReqLock) {
+ x509ReqText = X509_REQ_print(this.x509ReqPtr);
+ }
+ if (x509ReqText != null) {
+ /* let Java do the modified UTF-8 conversion */
+ return new String(x509ReqText, Charset.forName("UTF-8"));
+ } else {
+ System.out.println("toString: x509ReqTest == null");
+ }
+ }
+
+ return super.toString();
+ }
+
+ /**
+ * Frees WolfSSLCertRequest native resources.
+ */
+ public synchronized void free() {
+
+ synchronized (stateLock) {
+ if (this.active == false) {
+ /* already freed, just return */
+ return;
+ }
+
+ synchronized (x509ReqLock) {
+ /* free native resources */
+ X509_REQ_free(this.x509ReqPtr);
+
+ /* free Java resources */
+ this.active = false;
+ this.x509ReqPtr = 0;
+ }
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void finalize() throws Throwable
+ {
+ this.free();
+ super.finalize();
+ }
+}
+
diff --git a/src/java/com/wolfssl/WolfSSLCertificate.java b/src/java/com/wolfssl/WolfSSLCertificate.java
index e0aab09..d839b41 100644
--- a/src/java/com/wolfssl/WolfSSLCertificate.java
+++ b/src/java/com/wolfssl/WolfSSLCertificate.java
@@ -730,7 +730,32 @@ public class WolfSSLCertificate {
* @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
+ * WolfSSL.NID_subject_alt_name
+ * @param value String value of extension to set. For keyUsage and
+ * extKeyUsage this should be a comma-delimited list.
+ * For subjectAltName, this is a single value. Possible
+ * values for keyUsage and extKeyUsage are:
+ *
+ * NID_key_usage:
+ * digitalSignature
+ * nonRepudiation
+ * contentCommitment
+ * keyEncipherment
+ * dataEncipherment
+ * keyAgreement
+ * keyCertSign
+ * cRLSign
+ * encipherOnly
+ * decipherOnly
+ *
+ * NID_ext_key_usage:
+ * serverAuth
+ * clientAuth
+ * codeSigning
+ * emailProtection
+ * timeStamping
+ * OCSPSigning
+ *
* @param isCritical Boolean flag indicating if this extension is
* critical
*
@@ -785,8 +810,7 @@ public class WolfSSLCertificate {
* - 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
+ * WolfSSL.NID_basic_constraints
* @param value Boolean value of extension (true/false)
* @param isCritical Boolean flag indicating if this extension is
* critical
diff --git a/src/test/com/wolfssl/test/WolfSSLCertRequestTest.java b/src/test/com/wolfssl/test/WolfSSLCertRequestTest.java
new file mode 100644
index 0000000..d7c80b3
--- /dev/null
+++ b/src/test/com/wolfssl/test/WolfSSLCertRequestTest.java
@@ -0,0 +1,608 @@
+/* WolfSSLCertRequestTest.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.test;
+
+import org.junit.Test;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import java.security.PublicKey;
+import java.security.PrivateKey;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+
+import com.wolfssl.WolfSSL;
+import com.wolfssl.WolfSSLX509Name;
+import com.wolfssl.WolfSSLCertRequest;
+import com.wolfssl.WolfSSLException;
+import com.wolfssl.WolfSSLJNIException;
+
+/**
+ * @author wolfSSL
+ */
+public class WolfSSLCertRequestTest {
+ public final static int TEST_FAIL = -1;
+ public final static int TEST_SUCCESS = 0;
+
+ public static String cliKeyDer = "examples/certs/client-key.der";
+ public static String cliKeyPem = "examples/certs/client-key.pem";
+ public static String cliKeyPubDer = "examples/certs/client-keyPub.der";
+ public static String cliEccKeyDer = "examples/certs/ecc-client-key.der";
+ public static String cliEccKeyPem = "examples/certs/ecc-client-key.pem";
+
+ @BeforeClass
+ public static void setCertPaths() throws WolfSSLException {
+
+ System.out.println("WolfSSLCertRequest Class");
+
+ try {
+ WolfSSL.loadLibrary();
+ } catch (UnsatisfiedLinkError ule) {
+ fail("failed to load native JNI library");
+ }
+
+ cliKeyDer = WolfSSLTestCommon.getPath(cliKeyDer);
+ cliKeyPubDer = WolfSSLTestCommon.getPath(cliKeyPubDer);
+ }
+
+ /* 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
+ public void testAddAttribute()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException {
+
+ System.out.print("\taddAttribute()");
+
+ if (!WolfSSL.certReqEnabled()) {
+ /* WOLFSSL_CERT_REQ / --enable-certreq not enabled in wolfSSL */
+ System.out.println("\t\t\t... skipped");
+ return;
+ }
+
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+ assertNotNull(req);
+
+ /* Test adding supported attributes by NID */
+ req.addAttribute(WolfSSL.NID_pkcs9_challengePassword,
+ "12345".getBytes());
+ req.addAttribute(WolfSSL.NID_serialNumber,
+ "12345".getBytes());
+ req.addAttribute(WolfSSL.NID_pkcs9_unstructuredName,
+ "12345".getBytes());
+ req.addAttribute(WolfSSL.NID_pkcs9_contentType,
+ "12345".getBytes());
+ req.addAttribute(WolfSSL.NID_surname,
+ "12345".getBytes());
+ req.addAttribute(WolfSSL.NID_initials,
+ "12345".getBytes());
+ req.addAttribute(WolfSSL.NID_givenName,
+ "12345".getBytes());
+ req.addAttribute(WolfSSL.NID_dnQualifier,
+ "12345".getBytes());
+
+ /* Adding unsupported NID should throw exception */
+ try {
+ req.addAttribute(123456,
+ "12345".getBytes());
+ System.out.println("\t\t\t... failed");
+ fail("Unsupported NID did not throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ req.free();
+ System.out.println("\t\t\t... passed");
+ }
+
+ @Test
+ public void testAddExtension()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException {
+
+ System.out.print("\taddExtension()");
+
+ if (!WolfSSL.certReqEnabled()) {
+ /* WOLFSSL_CERT_REQ / --enable-certreq not enabled in wolfSSL */
+ System.out.println("\t\t\t... skipped");
+ return;
+ }
+
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+ assertNotNull(req);
+
+ /* Test adding supported extensions by NID */
+
+ /* 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 */
+ if (WolfSSL.getLibVersionHex() <= 0x05006003) {
+ req.addExtension(WolfSSL.NID_key_usage,
+ "digitalSignature,keyAgreement", false);
+ req.addExtension(WolfSSL.NID_ext_key_usage,
+ "serverAuth,clientAuth", false);
+ }
+ req.addExtension(WolfSSL.NID_subject_alt_name,
+ "my test altName", false);
+
+ /* Adding unsupported NID should throw exception */
+ try {
+ req.addExtension(123456, "12345", false);
+ System.out.println("\t\t\t... failed");
+ fail("Unsupported extension NID did not throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ /* Test boolean extension setting */
+ req.addExtension(WolfSSL.NID_basic_constraints, true, true);
+ req.addExtension(WolfSSL.NID_basic_constraints, false, true);
+
+ /* Adding unsupported NID should throw exception */
+ try {
+ req.addExtension(123456, true, false);
+ System.out.println("\t\t\t... failed");
+ fail("Unsupported extension NID did not throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ req.free();
+ System.out.println("\t\t\t... passed");
+ }
+
+ @Test
+ public void testSetVersion()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException {
+
+ System.out.print("\tsetVersion()");
+
+ if (!WolfSSL.certReqEnabled()) {
+ /* WOLFSSL_CERT_REQ / --enable-certreq not enabled in wolfSSL */
+ System.out.println("\t\t\t... skipped");
+ return;
+ }
+
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+ assertNotNull(req);
+
+ req.setVersion(0);
+ req.setVersion(1);
+
+ /* Negative versions should throw exception */
+ try {
+ req.setVersion(-100);
+ System.out.println("\t\t\t... failed");
+ fail("Negative version should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ req.free();
+ System.out.println("\t\t\t... passed");
+ }
+
+ @Test
+ public void testSetPublicKeyFile()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException {
+
+ System.out.print("\tsetPublicKey(file)");
+
+ if (!WolfSSL.certReqEnabled()) {
+ /* WOLFSSL_CERT_REQ / --enable-certreq not enabled in wolfSSL */
+ System.out.println("\t\t... skipped");
+ return;
+ }
+
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+ assertNotNull(req);
+
+ /* RSA */
+ req.setPublicKey(cliKeyPubDer, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ req.setPublicKey(cliKeyPem, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_PEM);
+
+ /* ECC */
+ req.setPublicKey(cliEccKeyDer, WolfSSL.ECDSAk,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ req.setPublicKey(cliEccKeyPem, WolfSSL.ECDSAk,
+ WolfSSL.SSL_FILETYPE_PEM);
+
+ /* Test bad key type */
+ try {
+ req.setPublicKey(cliKeyPubDer, 12345,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ System.out.println("\t\t... failed");
+ fail("bad key type should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ /* Test bad file type */
+ try {
+ req.setPublicKey(cliKeyPubDer, WolfSSL.RSAk, 12345);
+ System.out.println("\t\t... failed");
+ fail("bad file type should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ /* Test null file String */
+ try {
+ req.setPublicKey((String)null, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ System.out.println("\t\t... failed");
+ fail("null PublicKey should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ /* Test file that does not exist */
+ try {
+ req.setPublicKey("badfile", WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ System.out.println("\t\t... failed");
+ fail("Bad path to PublicKey should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ req.free();
+ System.out.println("\t\t... passed");
+ }
+
+ @Test
+ public void testSetPublicKeyArray()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException {
+
+ System.out.print("\tsetPublicKey(array)");
+
+ if (!WolfSSL.certReqEnabled()) {
+ /* WOLFSSL_CERT_REQ / --enable-certreq not enabled in wolfSSL */
+ System.out.println("\t\t... skipped");
+ return;
+ }
+
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+ assertNotNull(req);
+
+ byte[] cliKeyRSADer = Files.readAllBytes(Paths.get(cliKeyDer));
+ byte[] cliKeyRSAPem = Files.readAllBytes(Paths.get(cliKeyPem));
+ byte[] cliKeyECCDer = Files.readAllBytes(Paths.get(cliEccKeyDer));
+ byte[] cliKeyECCPem = Files.readAllBytes(Paths.get(cliEccKeyPem));
+
+ /* RSA */
+ req.setPublicKey(cliKeyRSADer, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ req.setPublicKey(cliKeyRSAPem, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_PEM);
+
+ /* ECC */
+ req.setPublicKey(cliKeyECCDer, WolfSSL.ECDSAk,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ req.setPublicKey(cliKeyECCPem, WolfSSL.ECDSAk,
+ WolfSSL.SSL_FILETYPE_PEM);
+
+ /* Test bad key type */
+ try {
+ req.setPublicKey(cliKeyRSADer, 12345,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ System.out.println("\t\t... failed");
+ fail("bad key type should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ /* Test bad file type */
+ try {
+ req.setPublicKey(cliKeyRSADer, WolfSSL.RSAk, 12345);
+ System.out.println("\t\t... failed");
+ fail("bad file type should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ /* Test null file String */
+ try {
+ req.setPublicKey((byte[])null, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ System.out.println("\t\t... failed");
+ fail("null key array should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ /* Test zero-length byte array */
+ byte[] zeroArr = new byte[0];
+ try {
+ req.setPublicKey(zeroArr, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1);
+ System.out.println("\t\t... failed");
+ fail("Zero length pub key array should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ req.free();
+ System.out.println("\t\t... passed");
+ }
+
+ @Test
+ public void testSetPublicKeyObject()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException, NoSuchAlgorithmException {
+
+ System.out.print("\tsetPublicKey(PublicKey)");
+
+ if (!WolfSSL.certReqEnabled()) {
+ /* WOLFSSL_CERT_REQ / --enable-certreq not enabled in wolfSSL */
+ System.out.println("\t\t... skipped");
+ return;
+ }
+
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+ assertNotNull(req);
+
+ /* RSA: Set Public Key from generated java.security.PublicKey */
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(2048);
+ KeyPair keyPair = kpg.generateKeyPair();
+ PublicKey pubKey = keyPair.getPublic();
+ req.setPublicKey(pubKey);
+
+ /* ECC: Set Public Key from generated java.security.PublicKey */
+ KeyPairGenerator kpgEcc = KeyPairGenerator.getInstance("EC");
+ kpgEcc.initialize(256);
+ KeyPair keyPairEcc = kpgEcc.generateKeyPair();
+ PublicKey pubKeyEcc = keyPairEcc.getPublic();
+ req.setPublicKey(pubKeyEcc);
+
+ /* Test null PublicKey object */
+ try {
+ req.setPublicKey((PublicKey)null);
+ System.out.println("\t\t... failed");
+ fail("null PublicKey should throw exception");
+ } catch (WolfSSLException e) {
+ /* expected */
+ }
+
+ req.free();
+ System.out.println("\t\t... passed");
+ }
+
+ @Test
+ public void testGenCSR_UsingFiles()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException {
+
+ System.out.print("\tgen CSR using files");
+
+ if (!WolfSSL.certReqEnabled()) {
+ /* WOLFSSL_CERT_REQ / --enable-certreq not enabled in wolfSSL */
+ System.out.println("\t\t... skipped");
+ return;
+ }
+
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+ assertNotNull(req);
+
+ /* Set Subject Name */
+ WolfSSLX509Name subjectName = GenerateTestSubjectName();
+ assertNotNull(subjectName);
+ req.setSubjectName(subjectName);
+
+ /* Set Public Key from file */
+ req.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 */
+ req.addExtension(WolfSSL.NID_key_usage,
+ "digitalSignature,keyEncipherment,dataEncipherment", false);
+
+ req.addExtension(WolfSSL.NID_ext_key_usage,
+ "clientAuth,serverAuth", false);
+ }
+ req.addExtension(WolfSSL.NID_subject_alt_name,
+ "test.wolfssl.com", false);
+ req.addExtension(WolfSSL.NID_basic_constraints, true, true);
+
+ /* Sign CSR */
+ req.signRequest(cliKeyDer, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1, "SHA256");
+
+ /* Output to DER and PEM */
+ byte[] derCsr = req.getDer();
+ byte[] pemCsr = req.getPem();
+
+ assertNotNull(derCsr);
+ assertTrue(derCsr.length > 0);
+ assertNotNull(pemCsr);
+ assertTrue(pemCsr.length > 0);
+
+ /* Free native memory */
+ subjectName.free();
+ req.free();
+
+ System.out.println("\t\t... passed");
+ }
+
+ @Test
+ public void testGenCSR_UsingBuffers()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException {
+
+ System.out.print("\tgen CSR using buffers");
+
+ if (!WolfSSL.certReqEnabled()) {
+ /* WOLFSSL_CERT_REQ / --enable-certreq not enabled in wolfSSL */
+ System.out.println("\t\t... skipped");
+ return;
+ }
+
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+ assertNotNull(req);
+
+ /* Set Subject Name */
+ WolfSSLX509Name subjectName = GenerateTestSubjectName();
+ assertNotNull(subjectName);
+ req.setSubjectName(subjectName);
+
+ /* Set Public Key from file */
+ byte[] pubKey = Files.readAllBytes(Paths.get(cliKeyPubDer));
+ req.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 */
+ req.addExtension(WolfSSL.NID_key_usage,
+ "digitalSignature,keyEncipherment,dataEncipherment", false);
+ req.addExtension(WolfSSL.NID_ext_key_usage,
+ "clientAuth,serverAuth", false);
+ }
+ req.addExtension(WolfSSL.NID_subject_alt_name,
+ "test.wolfssl.com", false);
+ req.addExtension(WolfSSL.NID_basic_constraints, true, true);
+
+ /* Sign CSR */
+ byte[] privKey = Files.readAllBytes(Paths.get(cliKeyDer));
+ req.signRequest(privKey, WolfSSL.RSAk,
+ WolfSSL.SSL_FILETYPE_ASN1, "SHA256");
+
+ /* Output to DER and PEM */
+ byte[] derCsr = req.getDer();
+ byte[] pemCsr = req.getPem();
+
+ assertNotNull(derCsr);
+ assertTrue(derCsr.length > 0);
+ assertNotNull(pemCsr);
+ assertTrue(pemCsr.length > 0);
+
+ /* Free native memory */
+ subjectName.free();
+ req.free();
+
+ System.out.println("\t\t... passed");
+ }
+
+ @Test
+ public void testGenCSR_UsingJavaClasses()
+ throws WolfSSLException, WolfSSLJNIException, IOException,
+ CertificateException, NoSuchAlgorithmException {
+
+ System.out.print("\tgen CSR using Java classes");
+
+ if (!WolfSSL.certReqEnabled()) {
+ /* WOLFSSL_CERT_REQ / --enable-certreq not enabled in wolfSSL */
+ System.out.println("\t... skipped");
+ return;
+ }
+
+ WolfSSLCertRequest req = new WolfSSLCertRequest();
+ assertNotNull(req);
+
+ /* Set Subject Name */
+ WolfSSLX509Name subjectName = GenerateTestSubjectName();
+ assertNotNull(subjectName);
+ req.setSubjectName(subjectName);
+
+ /* Set Public Key from generated java.security.PublicKey */
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(2048);
+ KeyPair keyPair = kpg.generateKeyPair();
+ PublicKey pubKey = keyPair.getPublic();
+ req.setPublicKey(pubKey);
+
+ /* Set Extensions */
+ if (WolfSSL.getLibVersionHex() > 0x05006003) {
+ /* Key Usage and Extended Key Usage only work with wolfSSL
+ * later than 5.6.3 */
+ req.addExtension(WolfSSL.NID_key_usage,
+ "digitalSignature,keyEncipherment,dataEncipherment", false);
+ req.addExtension(WolfSSL.NID_ext_key_usage,
+ "clientAuth,serverAuth", false);
+ }
+ req.addExtension(WolfSSL.NID_subject_alt_name,
+ "test.wolfssl.com", false);
+ req.addExtension(WolfSSL.NID_basic_constraints, true, true);
+
+ /* Sign CSR, with java.security.PrivateKey */
+ PrivateKey privKey = keyPair.getPrivate();
+ req.signRequest(privKey, "SHA256");
+
+ /* Output to DER and PEM */
+ byte[] derCsr = req.getDer();
+ byte[] pemCsr = req.getPem();
+
+ assertNotNull(derCsr);
+ assertTrue(derCsr.length > 0);
+ assertNotNull(pemCsr);
+ assertTrue(pemCsr.length > 0);
+
+ /* Free native memory */
+ subjectName.free();
+ req.free();
+
+ System.out.println("\t... passed");
+ }
+
+ /* Utility method if needed for testing, print out CSR array to file */
+ private void writeOutCsrFile(byte[] csr, String path)
+ throws IOException {
+ Files.write(new File(path).toPath(), csr);
+ }
+}
+
diff --git a/src/test/com/wolfssl/test/WolfSSLTestSuite.java b/src/test/com/wolfssl/test/WolfSSLTestSuite.java
index 4bd6762..7adf93d 100644
--- a/src/test/com/wolfssl/test/WolfSSLTestSuite.java
+++ b/src/test/com/wolfssl/test/WolfSSLTestSuite.java
@@ -31,7 +31,8 @@ import org.junit.runners.Suite;
WolfSSLSessionTest.class,
WolfCryptRSATest.class,
WolfCryptECCTest.class,
- WolfSSLCertificateTest.class
+ WolfSSLCertificateTest.class,
+ WolfSSLCertRequestTest.class
})