From 4c4783fe46a1c76627897240066484104821a89c Mon Sep 17 00:00:00 2001
From: gaubansa
Date: Tue, 17 Jun 2025 20:31:19 +0530
Subject: [PATCH 1/2] server cert made as optional and also server cert can be
passed as cert chain
---
src/main/java/Api/BatchUploadwithMTLSApi.java | 17 ++---
.../pgpBatchUpload/BatchUploadUtility.java | 39 +++++++----
.../MutualAuthUploadUtility.java | 65 ++++++++++++-------
3 files changed, 75 insertions(+), 46 deletions(-)
diff --git a/src/main/java/Api/BatchUploadwithMTLSApi.java b/src/main/java/Api/BatchUploadwithMTLSApi.java
index b5793379..9ccdf1cc 100644
--- a/src/main/java/Api/BatchUploadwithMTLSApi.java
+++ b/src/main/java/Api/BatchUploadwithMTLSApi.java
@@ -3,6 +3,7 @@
import java.io.File;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
+import java.util.Collection;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -30,9 +31,9 @@ public class BatchUploadwithMTLSApi {
* @param inputFile The file to be uploaded.
* @param environmentHostname The environment hostname (e.g., secure-batch-test.cybersource.com).
* @param pgpEncryptionCertPath Path to the PGP encryption certificate.
- * @param keystorePath Path to the JKS keystore file.
+ * @param keystorePath Path to the JKS keystore file containing client certificates.
* @param keystorePassword Password for the keystore.
- * @param truststorePath Path to the truststore file.
+ * @param truststorePath Path to the JKS truststore file containing trusted server certificates. Optional: Can be null if not required.
* @param truststorePassword Password for the truststore.
* @return ApiResponse containing the server response as a String.
* @throws ApiException If an API error occurs.
@@ -56,9 +57,9 @@ public ApiResponse uploadBatchAPI(File inputFile, String environmentHost
* @param inputFile The file to be uploaded.
* @param environmentHostname The environment hostname (e.g., api.cybersource.com).
* @param pgpEncryptionCertPath Path to the PGP encryption certificate.
- * @param clientCertP12FilePath Path to the PKCS#12 client certificate file.
+ * @param clientCertP12FilePath Path to the PKCS#12 client certificate file (.p12 or .pfx).
* @param clientCertP12Password Password for the PKCS#12 client certificate.
- * @param serverTrustCertPath Path to the server trust certificate.
+ * @param serverTrustCertPath Path to the server trust certificate(s) in PEM format. Optional: Can be null if not required.
* @return ApiResponse containing the server response as a String.
* @throws ApiException If an API error occurs.
* @throws Exception If a general error occurs.
@@ -83,20 +84,20 @@ public ApiResponse uploadBatchAPI(File inputFile, String environmentHost
* @param pgpPublicKey The PGP public key for encryption.
* @param clientPrivateKey The client's private key.
* @param clientCert The client's X509 certificate.
- * @param serverTrustCert The server's trust X509 certificate.
+ * @param serverTrustCerts A collection of server's trusted X509 certificates (can be a certificate chain). Optional: Can be null or empty if not required.
* @return ApiResponse containing the server response as a String.
* @throws ApiException If an API error occurs.
* @throws Exception If a general error occurs.
*/
- public ApiResponse uploadBatchAPI(File inputFile, String environmentHostname, PGPPublicKey pgpPublicKey, PrivateKey clientPrivateKey, X509Certificate clientCert , X509Certificate serverTrustCert) throws ApiException, Exception {
+ public ApiResponse uploadBatchAPI(File inputFile, String environmentHostname, PGPPublicKey pgpPublicKey, PrivateKey clientPrivateKey, X509Certificate clientCert , Collection serverTrustCerts) throws ApiException, Exception {
logger.info("Starting batch upload with client private key and certs for given file");
- BatchUploadUtility.validateBatchApiKeysInputs(inputFile, environmentHostname, pgpPublicKey, clientPrivateKey, clientCert, serverTrustCert);
+ BatchUploadUtility.validateBatchApiKeysInputs(inputFile, environmentHostname, pgpPublicKey, clientPrivateKey, clientCert, serverTrustCerts);
String endpoint = "/pts/v1/transaction-batch-upload";
String endpointUrl = BatchUploadUtility.getEndpointUrl(environmentHostname, endpoint);
byte[] encryptedPgpBytes = PgpEncryptionUtility.handlePGPEncrypt(inputFile, pgpPublicKey);
return MutualAuthUploadUtility.handleUploadOperationUsingPrivateKeyAndCerts(
encryptedPgpBytes, endpointUrl, inputFile.getName(),
- clientPrivateKey, clientCert, serverTrustCert
+ clientPrivateKey, clientCert, serverTrustCerts
);
}
diff --git a/src/main/java/utilities/pgpBatchUpload/BatchUploadUtility.java b/src/main/java/utilities/pgpBatchUpload/BatchUploadUtility.java
index 2c9af921..b72927e8 100644
--- a/src/main/java/utilities/pgpBatchUpload/BatchUploadUtility.java
+++ b/src/main/java/utilities/pgpBatchUpload/BatchUploadUtility.java
@@ -12,7 +12,10 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
@@ -33,21 +36,27 @@ public class BatchUploadUtility {
private static final Logger logger = LogManager.getLogger(BatchUploadUtility.class);
private static final long MAX_FILE_SIZE_BYTES = 75 * 1024 * 1024;
-
- /**
- * Loads an X509 certificate from a PEM file.
+
+ /**
+ * Loads X509 certificates from a PEM file.
*
* @param certFilePath The file path to the PEM certificate file.
- * @return The loaded X509Certificate object.
+ * @return The loaded X509Certificate(s) as a Collection.
* @throws CertificateException If the certificate cannot be parsed or is invalid.
* @throws IOException If the file cannot be read or does not exist.
*/
- public static X509Certificate loadCertificateFromPemFile(String certFilePath) throws CertificateException, IOException {
- try (FileInputStream inStream = new FileInputStream(certFilePath)) {
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- return (X509Certificate) cf.generateCertificate(inStream);
- }
- }
+ public static Collection loadCertificatesFromPemFile(String certFilePath) throws CertificateException, IOException {
+ try (FileInputStream inStream = new FileInputStream(certFilePath)) {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ Collection extends java.security.cert.Certificate> certs = cf.generateCertificates(inStream);
+ // Cast to X509Certificate
+ List x509Certs = new ArrayList<>();
+ for (java.security.cert.Certificate cert : certs) {
+ x509Certs.add((X509Certificate) cert);
+ }
+ return x509Certs;
+ }
+ }
/**
* Reads a PGP public key from the specified file.
@@ -114,7 +123,8 @@ public static void validateBatchApiJKSInputs(File inputFile, String environmentH
}
validatePathAndFile(pgpEncryptionCertPath, "PGP Encryption Cert Path");
validatePathAndFile(keystorePath, "Keystore Path");
- validatePathAndFile(truststorePath, "Truststore Path");
+ if (!StringUtils.isEmpty(truststorePath))
+ validatePathAndFile(truststorePath, "Truststore Path");
}
/**
@@ -135,7 +145,8 @@ public static void validateBatchApiP12Inputs(File inputFile, String environmentH
}
validatePathAndFile(pgpEncryptionCertPath, "PGP Encryption Cert Path");
validatePathAndFile(clientCertP12FilePath, "Client Cert P12 File Path");
- validatePathAndFile(serverTrustCertPath, "Server Trust Cert Path");
+ if (!StringUtils.isEmpty(serverTrustCertPath))
+ validatePathAndFile(serverTrustCertPath, "Server Trust Cert Path");
}
/**
@@ -149,7 +160,7 @@ public static void validateBatchApiP12Inputs(File inputFile, String environmentH
* @param serverTrustCert The server trust X509 certificate.
* @throws Exception If any validation fails.
*/
- public static void validateBatchApiKeysInputs(File inputFile, String environmentHostname, PGPPublicKey pgpPublicKey, PrivateKey clientPrivateKey, X509Certificate clientCert , X509Certificate serverTrustCert) throws Exception{
+ public static void validateBatchApiKeysInputs(File inputFile, String environmentHostname, PGPPublicKey pgpPublicKey, PrivateKey clientPrivateKey, X509Certificate clientCert , Collection serverTrustCert) throws Exception{
validateInputFile(inputFile);
if(StringUtils.isEmpty(environmentHostname)) {
logger.error("Environment Host Name for Batch Upload API cannot be null or empty.");
@@ -158,7 +169,7 @@ public static void validateBatchApiKeysInputs(File inputFile, String environment
if (pgpPublicKey == null) throw new IllegalArgumentException("PGP Public Key is null");
if (clientPrivateKey == null) throw new IllegalArgumentException("Client Private Key is null");
if (clientCert == null) throw new IllegalArgumentException("Client Certificate is null");
- if (serverTrustCert == null) throw new IllegalArgumentException("Server Trust Certificate is null");
+ //if (serverTrustCert == null) throw new IllegalArgumentException("Server Trust Certificate is null"); serverTrustCert is optional so can be null
}
/**
diff --git a/src/main/java/utilities/pgpBatchUpload/MutualAuthUploadUtility.java b/src/main/java/utilities/pgpBatchUpload/MutualAuthUploadUtility.java
index 2d08e817..7bbb63ef 100644
--- a/src/main/java/utilities/pgpBatchUpload/MutualAuthUploadUtility.java
+++ b/src/main/java/utilities/pgpBatchUpload/MutualAuthUploadUtility.java
@@ -12,6 +12,7 @@
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.util.Collection;
import java.util.UUID;
import javax.net.ssl.KeyManagerFactory;
@@ -52,7 +53,7 @@ public class MutualAuthUploadUtility {
* @param fileName The name of the file to be uploaded (will be suffixed with .pgp)
* @param keystorePath The file path to the JKS keystore containing client certificates
* @param keystorePassword The password for the JKS keystore
- * @param truststorePath The file path to the JKS truststore containing trusted server certificates
+ * @param truststorePath (Optional) The file path to the JKS truststore containing trusted server certificates. Can be null if not required.
* @param truststorePassword The password for the JKS truststore
* @return ApiResponse containing the upload response details
* @throws IOException If file operations or network communication fails
@@ -67,7 +68,7 @@ public static ApiResponse handleUploadOperationWithJKS(byte[] encryptedP
NoSuchAlgorithmException, CertificateException, KeyManagementException, UnrecoverableKeyException {
KeyStore clientKeyStore = KeyStore.getInstance("JKS");
- KeyStore serverTrustStore = KeyStore.getInstance("JKS");
+ KeyStore serverTrustStore = null;
// Load the JKS keyStore using try-with-resources
try (FileInputStream keyStoreFile = new FileInputStream(keystorePath)) {
@@ -75,8 +76,11 @@ public static ApiResponse handleUploadOperationWithJKS(byte[] encryptedP
}
// Load the JKS trustStore using try-with-resources
- try (FileInputStream trustStoreFile = new FileInputStream(truststorePath)) {
- serverTrustStore.load(trustStoreFile, truststorePassword);
+ if(!StringUtils.isEmpty(truststorePath)) {
+ serverTrustStore = KeyStore.getInstance("JKS");
+ try (FileInputStream trustStoreFile = new FileInputStream(truststorePath)) {
+ serverTrustStore.load(trustStoreFile, truststorePassword);
+ }
}
try {
@@ -89,14 +93,14 @@ public static ApiResponse handleUploadOperationWithJKS(byte[] encryptedP
}
/**
- * Handles file upload operation using P12/PFX keystore and PEM server certificate for mutual authentication.
- *
- * @param encryptedPgpBytes The encrypted PGP file content as byte array
+ * Handles file upload operation using P12/PFX keystore and PEM server certificate(s) for mutual authentication
+ *
+ * @param encryptedPgpBytes The encrypted PGP file content as a byte array
* @param endpointUrl The target URL endpoint for file upload
* @param fileName The name of the file to be uploaded (will be suffixed with .pgp)
* @param p12FilePath The file path to the P12/PFX keystore containing client certificates
* @param p12FilePassword The password for the P12/PFX keystore
- * @param serverTrustCertPath The file path to the PEM file containing server trust certificate
+ * @param serverTrustCertPath (Optional) The file path to the PEM file containing one or more server trust certificates. Can be null if not required
* @return ApiResponse containing the upload response details
* @throws IOException If file operations or network communication fails
* @throws KeyStoreException If keystore operations fail
@@ -108,14 +112,24 @@ public static ApiResponse handleUploadOperationWithJKS(byte[] encryptedP
public static ApiResponse handleUploadOperationUsingP12orPfx(byte[] encryptedPgpBytes, String endpointUrl, String fileName, String p12FilePath, char[] p12FilePassword, String serverTrustCertPath) throws IOException, KeyStoreException,
NoSuchAlgorithmException, CertificateException, KeyManagementException, UnrecoverableKeyException {
- X509Certificate serverTrustCert;
+ Collection serverTrustCert;
KeyStore clientKeyStore;
+ KeyStore serverTrustStore =null;
- try {
- serverTrustCert = BatchUploadUtility.loadCertificateFromPemFile(serverTrustCertPath);
- } catch (CertificateException e) {
- logger.error("Error loading certificate from PEM file", e);
- throw new CertificateException("Failed to load certificate from PEM file: " + serverTrustCertPath, e);
+ if(!StringUtils.isEmpty(serverTrustCertPath)) {
+ try {
+ serverTrustCert = BatchUploadUtility.loadCertificatesFromPemFile(serverTrustCertPath);
+ } catch (CertificateException e) {
+ logger.error("Error loading certificate from PEM file", e);
+ throw new CertificateException("Failed to load certificate from PEM file: " + serverTrustCertPath, e);
+ }
+ serverTrustStore = KeyStore.getInstance("JKS");
+ serverTrustStore.load(null, null);
+ int i = 0;
+ for (X509Certificate cert : serverTrustCert) {
+ serverTrustStore.setCertificateEntry("server-" + i, cert);
+ i++;
+ }
}
clientKeyStore = KeyStore.getInstance("PKCS12", new BouncyCastleProvider());
@@ -124,11 +138,7 @@ public static ApiResponse handleUploadOperationUsingP12orPfx(byte[] encr
try (FileInputStream file = new FileInputStream(new File(p12FilePath))) {
clientKeyStore.load(file, p12FilePassword);
}
-
- KeyStore serverTrustStore = KeyStore.getInstance("JKS");
- serverTrustStore.load(null, null);
- serverTrustStore.setCertificateEntry("server", serverTrustCert);
-
+
try {
OkHttpClient client = getOkHttpClientForMutualAuth(clientKeyStore, serverTrustStore, p12FilePassword);
return uploadFile(encryptedPgpBytes, fileName, endpointUrl, client);
@@ -146,7 +156,7 @@ public static ApiResponse handleUploadOperationUsingP12orPfx(byte[] encr
* @param fileName The name of the file to be uploaded (will be suffixed with .pgp)
* @param clientPrivateKey The client's private key for authentication
* @param clientCert The client's X509 certificate
- * @param serverTrustCert The server's trusted X509 certificate
+ * @param serverTrustCerts (Optional) A collection of server's trusted X509 certificates (can be a certificate chain). Can be null or empty if not required.
* @return ApiResponse containing the upload response details
* @throws KeyStoreException If keystore operations fail
* @throws NoSuchAlgorithmException If required cryptographic algorithms are not available
@@ -155,7 +165,7 @@ public static ApiResponse handleUploadOperationUsingP12orPfx(byte[] encr
* @throws UnrecoverableKeyException If private key cannot be recovered
* @throws KeyManagementException If SSL key management fails
*/
- public static ApiResponse handleUploadOperationUsingPrivateKeyAndCerts(byte[] encryptedPgpBytes, String endpointUrl, String fileName, PrivateKey clientPrivateKey,X509Certificate clientCert,X509Certificate serverTrustCert) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException
+ public static ApiResponse handleUploadOperationUsingPrivateKeyAndCerts(byte[] encryptedPgpBytes, String endpointUrl, String fileName, PrivateKey clientPrivateKey, X509Certificate clientCert, Collection serverTrustCerts) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException
{
// Create a KeyStore containing the client private key and certificate
KeyStore clientKeyStore = KeyStore.getInstance("PKCS12");
@@ -164,9 +174,16 @@ public static ApiResponse handleUploadOperationUsingPrivateKeyAndCerts(b
clientKeyStore.setKeyEntry("client", clientPrivateKey, new char[] {}, new java.security.cert.Certificate[]{clientCert});
// Create a KeyStore containing the server's trusted certificate
- KeyStore serverTrustStore = KeyStore.getInstance("JKS");
- serverTrustStore.load(null, null);
- serverTrustStore.setCertificateEntry("server", serverTrustCert);
+ KeyStore serverTrustStore =null;
+ if(serverTrustCerts!=null && !serverTrustCerts.isEmpty()) {
+ serverTrustStore = KeyStore.getInstance("JKS");
+ serverTrustStore.load(null, null);
+ int i = 0;
+ for (X509Certificate cert : serverTrustCerts) {
+ serverTrustStore.setCertificateEntry("server-" + i, cert);
+ i++;
+ }
+ }
try {
OkHttpClient client = getOkHttpClientForMutualAuth(clientKeyStore, serverTrustStore, new char[] {});
From f2973aec029f3133ed95fe418da4ceb745c868e4 Mon Sep 17 00:00:00 2001
From: gaubansa
Date: Tue, 17 Jun 2025 21:12:11 +0530
Subject: [PATCH 2/2] adding code for disable ssl verification
---
.../MutualAuthUploadUtility.java | 72 ++++++++++++++-----
1 file changed, 54 insertions(+), 18 deletions(-)
diff --git a/src/main/java/utilities/pgpBatchUpload/MutualAuthUploadUtility.java b/src/main/java/utilities/pgpBatchUpload/MutualAuthUploadUtility.java
index 7bbb63ef..e90bcb0b 100644
--- a/src/main/java/utilities/pgpBatchUpload/MutualAuthUploadUtility.java
+++ b/src/main/java/utilities/pgpBatchUpload/MutualAuthUploadUtility.java
@@ -42,9 +42,12 @@
*
*/
public class MutualAuthUploadUtility {
-
+
private static final Logger logger = LogManager.getLogger(MutualAuthUploadUtility.class);
-
+
+ // Global variable to control SSL verification
+ private static boolean disableSslVerification = false;
+
/**
* Handles file upload operation using JKS keystore and truststore for mutual authentication.
*
@@ -193,6 +196,19 @@ public static ApiResponse handleUploadOperationUsingPrivateKeyAndCerts(b
throw new IOException("Failed to perform upload operation with private/cert keys ", e);
}
}
+
+ /**
+ * Sets whether SSL verification should be disabled.
+ * @param disable true to disable SSL verification, false to enable
+ * By default, SSL verification is enabled.
+ */
+ public static void setDisableSslVerification(boolean disable) {
+ logger.warn("Setting disableSslVerification to: " + disable);
+ if (disable) {
+ logger.warn("SSL verification is DISABLED. This setting is NOT SAFE for production and should NOT be used in production environments!");
+ }
+ disableSslVerification = disable;
+ }
/**
* Creates an OkHttpClient configured for mutual TLS authentication.
@@ -209,22 +225,42 @@ public static ApiResponse handleUploadOperationUsingPrivateKeyAndCerts(b
private static OkHttpClient getOkHttpClientForMutualAuth(KeyStore clientKeyStore, KeyStore serverTrustStore,
char[] keyPassword) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException,
KeyManagementException
- {
- // Set up KeyManager and TrustManager
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- kmf.init(clientKeyStore, keyPassword); // Use the provided password
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- tmf.init(serverTrustStore);
-
- // Create SSL context
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
-
- // Build OkHttpClient with mutual TLS
- return new OkHttpClient.Builder()
- .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tmf.getTrustManagers()[0])
- .build();
- }
+ {
+ if (disableSslVerification) {
+ logger.warn("SSL verification is DISABLED. This setting is NOT SAFE for production and should NOT be used in production environments!");
+ // Trust all certificates
+ X509TrustManager trustAllManager = new X509TrustManager() {
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {}
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {}
+ public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
+ };
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(clientKeyStore, keyPassword);
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(kmf.getKeyManagers(), new javax.net.ssl.TrustManager[]{trustAllManager}, new SecureRandom());
+
+ return new OkHttpClient.Builder()
+ .sslSocketFactory(sslContext.getSocketFactory(), trustAllManager)
+ .hostnameVerifier((hostname, session) -> true)
+ .build();
+ } else {
+ // Set up KeyManager and TrustManager
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(clientKeyStore, keyPassword); // Use the provided password
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(serverTrustStore);
+
+ // Create SSL context
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
+
+ // Build OkHttpClient with mutual TLS
+ return new OkHttpClient.Builder()
+ .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tmf.getTrustManagers()[0])
+ .build();
+ }
+ }
/**
* Uploads a file to the specified endpoint using the provided HTTP client.