11package io .openems .edge .controller .api .mqtt ;
22
3+ import org .bouncycastle .jce .provider .BouncyCastleProvider ;
4+ import org .bouncycastle .asn1 .pkcs .PrivateKeyInfo ;
5+ import org .bouncycastle .openssl .PEMKeyPair ;
6+ import org .bouncycastle .openssl .PEMParser ;
7+ import org .bouncycastle .openssl .jcajce .JcaPEMKeyConverter ;
8+
39import javax .net .ssl .*;
4- import java .io .FileInputStream ;
510import java .io .InputStream ;
6- import java .security . KeyFactory ;
7- import java .security .KeyStore ;
8- import java .security .PrivateKey ;
11+ import java .io . InputStreamReader ;
12+ import java .security .* ;
13+ import java .security .cert . CertificateException ;
914import java .security .cert .CertificateFactory ;
1015import java .security .cert .X509Certificate ;
11- import java .security .spec .PKCS8EncodedKeySpec ;
12- import java .util . ArrayList ;
13- import java .util . List ;
16+ import java .security .spec .InvalidKeySpecException ;
17+ import java .io . ByteArrayInputStream ;
18+ import java .io . IOException ;
1419
1520/**
1621 * This Utility class provides methods for handling MQTT-related operations.
@@ -25,105 +30,93 @@ public class MqttUtils {
2530 * server truststore information, allowing the creation of an SSLSocketFactory
2631 * with the configured security settings.
2732 *
28- * @param certPath The file path to the client's certificate.
29- * @param privateKeyPath The file path to the private key file.
30- * @param trustStorePath The file path to the server's truststore.
31- * @param trustStorePassword The password for accessing the server's truststore.
33+ * @param cert The client's certificate as String.
34+ * @param privateKey The private key as String.
35+ * @param trustStore The server's trust store as String.
3236 * @return An SSLSocketFactory configured with the specified security settings.
3337 * @throws RuntimeException If there is an error during the creation of the
3438 * SSLSocketFactory.
3539 */
3640
37- public static SSLSocketFactory createSslSocketFactory (String certPath , String privateKeyPath , String trustStorePath ,
38- String trustStorePassword ) {
41+ public static SSLSocketFactory createSslSocketFactory (String cert , String privateKey , String trustStore ) {
3942 try {
40- X509Certificate clientCertificate = loadClientCertificate (certPath );
41-
42- PrivateKey privateKey = loadPrivateKey (privateKeyPath );
43-
44- KeyManagerFactory keyManagerFactory = KeyManagerFactory
45- .getInstance (KeyManagerFactory .getDefaultAlgorithm ());
46- KeyStore clientKeyStore = KeyStore .getInstance (KeyStore .getDefaultType ());
47- clientKeyStore .load (null );
48- clientKeyStore .setCertificateEntry ("clientCert" , clientCertificate );
49- char pw [] = (trustStorePassword != null ) ? trustStorePassword .toCharArray () : null ;
50- clientKeyStore .setKeyEntry ("clientKey" , privateKey , pw ,
51- new java .security .cert .Certificate [] { clientCertificate });
52- keyManagerFactory .init (clientKeyStore , pw );
53-
54- TrustManagerFactory trustManagerFactory = TrustManagerFactory
55- .getInstance (TrustManagerFactory .getDefaultAlgorithm ());
56- trustManagerFactory .init (loadTrustStore (trustStorePath ));
43+ Security .addProvider (new BouncyCastleProvider ());
5744
58- SSLContext sslContext = SSLContext .getInstance ("TLS" );
59- sslContext .init (keyManagerFactory .getKeyManagers (), trustManagerFactory .getTrustManagers (), null );
60-
61- return sslContext .getSocketFactory ();
62- } catch (Exception e ) {
63- throw new RuntimeException ("Error creating SSLSocketFactory" , e );
64- }
65- }
66-
67- /**
68- * Loads a client certificate from a given path.
69- *
70- * @param certPath The path to the certificate file.
71- * @return The loaded client certificate.
72- * @throws Exception If an error occurs while loading the certificate.
73- */
74- private static X509Certificate loadClientCertificate (String certPath ) throws Exception {
75- CertificateFactory certificateFactory = CertificateFactory .getInstance ("X.509" );
76- X509Certificate clientCertificate ;
77- try (InputStream certInputStream = new FileInputStream (certPath )) {
78- clientCertificate = (X509Certificate ) certificateFactory .generateCertificate (certInputStream );
79- return clientCertificate ;
80- }
8145
82- }
46+ // Load client certificate
47+ X509Certificate clientCert = loadCertificate (cert );
8348
84- /**
85- * Loads a trust store from a given path.
86- *
87- * @param trustStorePath The path to the trust store file.
88- * @return The loaded trust store.
89- * @throws Exception If an error occurs while loading the trust store.
90- */
91- private static KeyStore loadTrustStore (String trustStorePath ) throws Exception {
92- CertificateFactory cf = CertificateFactory .getInstance ("X.509" );
49+ // Load client private key
50+ PrivateKey clientKey = loadPrivateKey (privateKey );
51+
52+ // Load CA certificate
53+ X509Certificate caCert = loadCertificate (trustStore );
9354
94- List <X509Certificate > certificates = new ArrayList <>();
95- try (FileInputStream fis = new FileInputStream (trustStorePath )) {
96- while (fis .available () > 0 ) {
97- X509Certificate certificate = (X509Certificate ) cf .generateCertificate (fis );
98- certificates .add (certificate );
99- }
100- }
55+ // Create a KeyStore and add the CA certificate, client certificate, and private key
56+ KeyStore keyStore = KeyStore .getInstance ("PKCS12" );
57+ keyStore .load (null , null );
58+ keyStore .setCertificateEntry ("caCert" , caCert );
59+ keyStore .setCertificateEntry ("clientCert" , clientCert );
60+ keyStore .setKeyEntry ("clientKey" , clientKey , new char [0 ], new X509Certificate []{clientCert });
10161
102- KeyStore trustStore = KeyStore .getInstance (KeyStore .getDefaultType ());
103- trustStore .load (null );
62+ // Create a TrustManager that trusts the CA certificate
63+ TrustManagerFactory trustManagerFactory = TrustManagerFactory .getInstance (TrustManagerFactory .getDefaultAlgorithm ());
64+ trustManagerFactory .init (keyStore );
10465
105- int i = 0 ;
106- for (X509Certificate certificate : certificates ) {
107- String alias = "cert" + i ++;
108- trustStore .setCertificateEntry (alias , certificate );
109- }
66+ // Create a KeyManager that uses the client certificate and private key
67+ KeyManagerFactory keyManagerFactory = KeyManagerFactory .getInstance (KeyManagerFactory .getDefaultAlgorithm ());
68+ keyManagerFactory .init (keyStore , new char [0 ]);
11069
111- return trustStore ;
112- }
70+ // Create an SSLContext with the TrustManager and KeyManager
71+ SSLContext sslContext = SSLContext .getInstance ("TLS" );
72+ sslContext .init (keyManagerFactory .getKeyManagers (), trustManagerFactory .getTrustManagers (), new SecureRandom ());
11373
114- /**
115- * Loads a private key from a given path.
116- *
117- * @param privateKeyPath The path to the private key file.
118- * @return The loaded private key.
119- * @throws Exception If an error occurs while loading the private key.
120- */
121- private static PrivateKey loadPrivateKey (String privateKeyPath ) throws Exception {
122- try (FileInputStream keyInputStream = new FileInputStream (privateKeyPath )) {
123- byte [] keyBytes = keyInputStream .readAllBytes ();
124- PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec (keyBytes );
125- KeyFactory keyFactory = KeyFactory .getInstance ("RSA" );
126- return keyFactory .generatePrivate (keySpec );
74+ return sslContext .getSocketFactory ();
75+ } catch (Exception e ) {
76+ throw new RuntimeException ("Error creating SSLSocketFactory" , e );
12777 }
12878 }
79+
80+ /**
81+ * Loads an X.509 certificate from a PEM-encoded string.
82+ *
83+ * @param cert The PEM-encoded certificate string.
84+ * @return The X.509 certificate.
85+ * @throws IOException If an I/O error occurs.
86+ * @throws CertificateException If an error occurs while processing the certificate.
87+ */
88+ private static X509Certificate loadCertificate (String cert ) throws IOException , CertificateException {
89+ CertificateFactory cf = CertificateFactory .getInstance ("X.509" );
90+ try (InputStream is = new ByteArrayInputStream (cert .getBytes ())) {
91+ return (X509Certificate ) cf .generateCertificate (is );
92+ }
93+ }
94+
95+ /**
96+ * Loads a private key from a PEM-encoded string.
97+ *
98+ * @param privateKey The PEM-encoded private key string.
99+ * @return The private key.
100+ * @throws IOException If an I/O error occurs.
101+ * @throws NoSuchAlgorithmException If the specified algorithm is not available.
102+ * @throws InvalidKeySpecException If the private key cannot be generated.
103+ */
104+ private static PrivateKey loadPrivateKey (String privateKey ) throws IOException , NoSuchAlgorithmException , InvalidKeySpecException {
105+ try (PEMParser pemParser = new PEMParser (new InputStreamReader (new ByteArrayInputStream (privateKey .getBytes ())))) {
106+ Object obj = pemParser .readObject ();
107+ if (obj instanceof PEMKeyPair ) {
108+ // Handle RSA private key
109+ PEMKeyPair pemKeyPair = (PEMKeyPair ) obj ;
110+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter ().setProvider ("BC" );
111+ return converter .getPrivateKey (pemKeyPair .getPrivateKeyInfo ());
112+ } else if (obj instanceof PrivateKeyInfo ) {
113+ // Handle other private key formats
114+ PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo ) obj ;
115+ JcaPEMKeyConverter converter = new JcaPEMKeyConverter ().setProvider ("BC" );
116+ return converter .getPrivateKey (privateKeyInfo );
117+ } else {
118+ throw new InvalidKeySpecException ("Invalid private key format" );
119+ }
120+ }
121+ }
129122}
0 commit comments