@@ -30,24 +30,21 @@ public class CertificateGrabber {
3030 private static Logger log = LoggerFactory .getLogger (CertificateGrabber .class );
3131
3232 /**
33- * Retrieves the server certificate from the specified host and port.
33+ * Retrieves the full certificate chain from the specified host and port.
34+ * This includes the server certificate and all intermediate CA certificates,
35+ * which are required for proper TLS validation.
3436 *
35- * @param host
36- * @param port
37- * @throws Exception
37+ * @param host the hostname to connect to
38+ * @param port the port to connect to
39+ * @throws Exception if an error occurs while retrieving certificates
3840 */
3941 public static void retrieveCertificate (String host , int port ) throws Exception {
40- // Create a trust manager that captures certificates
41- final X509Certificate [] serverCert = new X509Certificate [1 ];
42+ // Create a trust manager that accepts all certificates (for retrieval only)
4243 TrustManager [] trustManagers = new TrustManager [] { new X509TrustManager () {
4344 public void checkClientTrusted (X509Certificate [] chain , String authType ) {
4445 }
4546
4647 public void checkServerTrusted (X509Certificate [] chain , String authType ) {
47- // Capture the server certificate
48- if (chain != null && chain .length > 0 ) {
49- serverCert [0 ] = chain [0 ];
50- }
5148 }
5249
5350 public X509Certificate [] getAcceptedIssuers () {
@@ -61,23 +58,52 @@ public X509Certificate[] getAcceptedIssuers() {
6158 SSLSocketFactory factory = sslContext .getSocketFactory ();
6259 try (SSLSocket socket = (SSLSocket ) factory .createSocket (host , port )) {
6360 socket .startHandshake ();
64- // Get the certificate chain
61+ // Get the full certificate chain
6562 SSLSession session = socket .getSession ();
6663 Certificate [] certs = session .getPeerCertificates ();
67- // Save the certificate
64+ // Save the full certificate chain
6865 if (certs != null && certs .length > 0 ) {
69- X509Certificate cert = (X509Certificate ) certs [0 ];
7066 // check for path to store the certificate
7167 String truststorePath = System .getProperty ("javax.net.ssl.trustStore" );
7268 if (truststorePath == null || truststorePath .isEmpty ()) {
7369 throw new IllegalStateException ("Truststore path is not set. Please set 'javax.net.ssl.trustStore' system property." );
7470 }
7571 String pemPath = truststorePath .substring (0 , truststorePath .lastIndexOf ('/' ));
76- log .info ("CertificateGrabber - pemPath: {}" , pemPath );
77- saveCertificate (cert , String .format ("%s/%s.pem" , pemPath , host ));
78- log .debug ("Certificate subject: {} issuer: {}\n serial number: {}\n valid from: {} to: {}" , cert .getSubjectX500Principal (), cert .getIssuerX500Principal (), cert .getSerialNumber (), cert .getNotBefore (), cert .getNotAfter ());
72+ log .info ("CertificateGrabber - pemPath: {}, chain length: {}" , pemPath , certs .length );
73+ // Save all certificates in the chain to a single PEM file
74+ saveCertificateChain (certs , String .format ("%s/%s.pem" , pemPath , host ));
75+ // Log info about each certificate in the chain
76+ for (int i = 0 ; i < certs .length ; i ++) {
77+ X509Certificate cert = (X509Certificate ) certs [i ];
78+ log .debug ("Certificate[{}] subject: {} issuer: {} serial: {} valid: {} to {}" , i , cert .getSubjectX500Principal (), cert .getIssuerX500Principal (), cert .getSerialNumber (), cert .getNotBefore (), cert .getNotAfter ());
79+ }
80+ }
81+ }
82+ }
83+
84+ /**
85+ * Saves the full certificate chain to a file in PEM format.
86+ * All certificates are written to a single file, which can then be
87+ * imported into a truststore.
88+ *
89+ * @param certs the certificate chain to save
90+ * @param fileName name of the file to save the certificates to
91+ * @throws Exception if an error occurs while saving the certificates
92+ */
93+ private static void saveCertificateChain (Certificate [] certs , String fileName ) throws Exception {
94+ // Save all certificates as PEM format in a single file
95+ try (FileWriter fw = new FileWriter (fileName ); PrintWriter pw = new PrintWriter (fw )) {
96+ for (int i = 0 ; i < certs .length ; i ++) {
97+ X509Certificate cert = (X509Certificate ) certs [i ];
98+ pw .println ("-----BEGIN CERTIFICATE-----" );
99+ pw .println (Base64 .encodeBase64String (cert .getEncoded ()));
100+ pw .println ("-----END CERTIFICATE-----" );
101+ if (i < certs .length - 1 ) {
102+ pw .println (); // blank line between certificates
103+ }
79104 }
80105 }
106+ log .info ("Certificate chain ({} certs) saved to: {}" , certs .length , fileName );
81107 }
82108
83109 /**
@@ -87,6 +113,7 @@ public X509Certificate[] getAcceptedIssuers() {
87113 * @param fileName name of the file to save the certificate to
88114 * @throws Exception if an error occurs while saving the certificate
89115 */
116+ @ SuppressWarnings ("unused" )
90117 private static void saveCertificate (X509Certificate cert , String fileName ) throws Exception {
91118 // Save as PEM format
92119 try (FileWriter fw = new FileWriter (fileName ); PrintWriter pw = new PrintWriter (fw )) {
0 commit comments