TLS/SSL java 中的 MQTT 连接

TLS/SSL Connection for MQTT in java

我正在研究 MQTT 协议。我配置了它的服务器并在 java 中使用它的 mosquitto 库在端口 1883 上执行了通信。 现在我想进行此通信 secure.What 我知道端口 8883 是为其基于 tls 的安全通信保留的。 它需要 X.509 证书。 为此,我找到了以下教程。

http://www.embedded101.com/Blogs/PaoloPatierno/entryid/366/mqtt-over-ssl-tls-with-the-m2mqtt-library-and-the-mosquitto-broker

但我的问题是

1.how 我们可以在 java 代码中生成这些证书吗?

2.how 我们可以根据上面的教程在 time.As 处使用多个证书吗?我们可以在 server.And 的 mosquitto.conf 文件中一次只指定一组证书然后我们需要重新启动服务器。(我不想这样做。)

3.how 我们能否让 运行 服务器知道这些新生成的证书。除了在服务器的 conf 文件中指定之外,还有其他方法可以做到这一点吗?

好的,我想您可能没有理解证书身份验证的工作原理。

它有 2 个部分(证明经纪人是它所说的人,然后证明连接的客户端是谁)

首先,经纪人将拥有 1 个向全世界标识它的证书。您将 Mosquitto 配置为在启动时使用此证书,并且永远不需要更改它。此证书将由 CA 签名。

传感器(客户端)将拥有 CA 证书的副本,当它们连接到代理时将使用该副本以确保它是它声称的身份。

其次,如果您想使用客户端证书来识别单独的传感器,那么它们也都需要一个证书。通常这将由与经纪人证书相同的 CA 签名,因此经纪人可以验证客户是否是他们声称的身份。可以将 Mosquitto 设置为使用证书 (use_identity_as_username true) 中的 CN 作为连接客户端的用户名,然后您可以使用 mosquitto_auth_plugin 跟踪证书中的 CN 并将 ACL 应用于控制谁可以使用什么主题。

至于在 java 中创建证书,我建议您查看此 question

颁发新证书时无需重新启动 Mosquitto。

    //add bcpkix-jdk15on-161, bcprov-jdk15on-1.52 and eclips pago-mqtt3.1 
    //lib in build path
    import java.io.*;
    import java.nio.file.*;
    import java.security.*;
    import java.security.cert.*;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import javax.net.ssl.*;
    import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
    import org.bouncycastle.jce.provider.*;
    import org.bouncycastle.openssl.*;
    import org.bouncycastle.openssl.PasswordFinder;
    import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
    import org.bouncycastle.util.io.pem.PemObject;
    import org.bouncycastle.util.io.pem.PemReader;
    import org.eclipse.paho.client.mqttv3.MqttClient;
    import org.eclipse.paho.client.mqttv3.MqttConnectOptions;

    public class SslUtil
    {

        @SuppressWarnings("deprecation")
        //It will return SSLSocketFactory
        public static SSLSocketFactory getSocketFactory (final String 
       caCrtFile, final String crtFile, final String keyFile,                                                     
                   final String password) throws Exception
        {
            try{
                Security.addProvider(new BouncyCastleProvider());

                X509Certificate caCert = 
                (X509Certificate)SslUtil.getCertificate(caCrtFile);
                X509Certificate cert = 
                (X509Certificate)SslUtil.getCertificate(crtFile);
                FileReader fileReader = new FileReader(keyFile);
                PEMParser parser = new PEMParser(fileReader);
                PEMKeyPair kp = (PEMKeyPair) parser.readObject();

                PrivateKeyInfo info = kp.getPrivateKeyInfo();

                PrivateKey rdKey = new JcaPEMKeyConverter().setProvider("BC")
                        .getPrivateKey(info);

                // CA certificate is used to authenticate server
                KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
                caKs.load(null, null);
                caKs.setCertificateEntry("ca-certificate", caCert);
                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init(caKs);

                // client key and certificates are sent to server so it can authenticate us
                KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
                ks.load(null, null);
                ks.setCertificateEntry("certificate", cert);
                ks.setKeyEntry("private-key", rdKey, password.toCharArray(), new java.security.cert.Certificate[]{cert});
                KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
                kmf.init(ks, password.toCharArray());

                // finally, create SSL socket factory
                SSLContext context = SSLContext.getInstance("TLSv1");
                context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

                return context.getSocketFactory();
            }catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
       //Get MqttClient for Subscripe Pulish
        public static void mqttClient(String caCrtFile,String clientCrtFilePath,String clientKeyFilePath,String password){
            try{

            String serverUrl = "ssl://serverip:8883";
            MqttClient client = new MqttClient(serverUrl, "consumerId" , null);
//this MyCallback class extends mqtt there we have to override some function //like message arriver etc
            client.setCallback(new MyCallback());
            MqttConnectOptions options = new MqttConnectOptions();
            options.setConnectionTimeout(60);
            options.setKeepAliveInterval(60);
            options.setSocketFactory(SslUtil.getSocketFactory(caCrtFile, clientCrtFilePath, clientKeyFilePath, password));
            client.connect(options);
            client.subscribe("topic", 0);
            }catch (Exception e) {
                System.out.println("#Exception  :"+e.getMessage());
            }
        }
       //start execution
        public static void main(String[] args) throws Exception {
            String caCrtFile = "path Certification Authority";
            String clientCrtFilePath ="path for client crt file";
            String clientKeyFilePath ="path of client key";


            String password = "password while generating files";


        mqttClient(caCrtFile,clientCrtFilePath,clientKeyFilePath,password);
        //  getCertificate(caCrtFile);
        }

        //return certificate
        public static java.security.cert.X509Certificate getCertificate(String pemfile) throws Exception
        {
            java.security.cert.X509Certificate cert = null;
            try {
                FileReader fRd = new FileReader(pemfile);
                final PemReader certReader = new PemReader(fRd);
                final PemObject certAsPemObject = certReader.readPemObject();
                if (!certAsPemObject.getType().equalsIgnoreCase("CERTIFICATE")) {
                    throw new Exception("Certificate file does not contain a certificate but a " + certAsPemObject.getType());
                }
                final byte[] x509Data = certAsPemObject.getContent();
                final CertificateFactory fact = CertificateFactory.getInstance("X509");
                cert = (X509Certificate) fact.generateCertificate(new ByteArrayInputStream(x509Data));
                if (!(cert instanceof X509Certificate)) {
                    throw new Exception("Certificate file does not contain an X509 certificate");
                }

            } catch (FileNotFoundException e) {
                throw new IOException("Can't find file " + pemfile);
            }catch (Exception e) {
                System.out.println("#Exceotion :"+e.getMessage());
            }
            return cert;
        }

    //retuen keyPair Object form client key
        public KeyPair decodeKeys(byte[] privKeyBits,byte[] pubKeyBits) 
              throws InvalidKeySpecException, NoSuchAlgorithmException {
              KeyFactory keyFactory=KeyFactory.getInstance("RSA");
              PrivateKey privKey=keyFactory.generatePrivate(new 
              PKCS8EncodedKeySpec(privKeyBits));
              PublicKey pubKey=keyFactory.generatePublic(new 
              X509EncodedKeySpec(pubKeyBits));
              return new KeyPair(pubKey,privKey);
            }
    }