java中MQTT的TLS / SSL连接

时间:2016-05-12 06:24:54

标签: java ssl mqtt iot

我正在研究MQTT协议。我配置了它的服务器并使用1883端口上的mosquitto库在java中进行了通信。 现在我想让这个通信安全。我知道端口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.我们可以用java代码生成这些证书吗?

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

3.我们可以让运行的服务器了解这些新生成的证书。除了在服务器的conf文件中指定外,还有其他方法吗?

2 个答案:

答案 0 :(得分:1)

好的,我想你很想知道证书认证的工作原理。

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

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

传感器(客户端)将拥有CA证书的副本,当他们连接到经纪人时将使用这些证书的副本,以确保它是声称的人。

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

至于在java中创建证书,我建议你看看这个question

发布新证书时无需重启Mosquitto。

答案 1 :(得分:0)

    //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);
            }
    }