如何修复与ip地址匹配的无主题替代名称

weylhg0b  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(451)

我为mqtt客户机使用了以下代码-:运行在vmware中的mqtt代理基于证书的身份验证。我正在通过windows系统中的代码运行mqtt客户机。

public class TestClient {

public static void main(String[] args) {
        String serverUrl = "ssl://192.168.5.12:8883";
        String caFilePath = "rootca.pem";
        String clientCrtFilePath = "Client.pem";
        String clientKeyFilePath = "Client.key";
        String mqttUserName = "guest";
        String mqttPassword = "123123";

        MqttClient client;
        try {
            client = new MqttClient(serverUrl, "2");
            MqttConnectOptions options = new MqttConnectOptions();
//          options.setUserName(mqttUserName);
//          options.setPassword(mqttPassword.toCharArray());
//          options.setSSLProperties(props);
            options.setConnectionTimeout(0);
            options.setKeepAliveInterval(300);
            options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1);

            SSLSocketFactory socketFactory = getSocketFactory(caFilePath,
                    clientCrtFilePath, clientKeyFilePath, "");
            options.setSocketFactory(socketFactory);

            System.out.println("starting connect the server...");
            client.connect(options);
            System.out.println("connected!");
            Thread.sleep(1000);

            client.subscribe(
                    "/u/56ca327d17531d08e76bddd4a215e37f5fd6082f7442151c4d3f1d100a0ffd4e",
                    0);
            client.disconnect();
            System.out.println("disconnected!");
        } catch (MqttException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static SSLSocketFactory getSocketFactory(final String caCrtFile,
            final String crtFile, final String keyFile, final String password)
            throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        // load CA certificate
        X509Certificate caCert = null;
        FileInputStream fis = new FileInputStream(caCrtFile);
        BufferedInputStream bis = new BufferedInputStream(fis);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        while (bis.available() > 0) {
            caCert = (X509Certificate) cf.generateCertificate(bis);
            // System.out.println(caCert.toString());
        }
        // load client certificate
        bis = new BufferedInputStream(new FileInputStream(crtFile));
        X509Certificate cert = null;
        while (bis.available() > 0) {
            cert = (X509Certificate) cf.generateCertificate(bis);
            // System.out.println(caCert.toString());
        }
        // load client private key
        PEMParser pemParser = new PEMParser(new FileReader(keyFile));
        Object object = pemParser.readObject();
        PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder()
                .build(password.toCharArray());
        JcaPEMKeyConverter converter = new JcaPEMKeyConverter()
                .setProvider("BC");
        KeyPair key;
        if (object instanceof PEMEncryptedKeyPair) {
            System.out.println("Encrypted key - we will use provided password");
            key = converter.getKeyPair(((PEMEncryptedKeyPair) object)
                    .decryptKeyPair(decProv));
        } else {
            System.out.println("Unencrypted key - no password needed");
            key = converter.getKeyPair((PEMKeyPair) object);
        }
        pemParser.close();

        // 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("X509");
        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", key.getPrivate(), 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.2");
        context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

        return context.getSocketFactory();
    }
  }

我得到下面的错误ip地址没有主题替代名称匹配

Unencrypted key - no password needed
starting connect the server...
MqttException (0) - javax.net.ssl.SSLHandshakeException: No subject alternative names matching IP address 192.168.5.12 found

我找了很多我没法修好请帮忙谢谢

zzwlnbp8

zzwlnbp81#

你有三个选择。
更改代理所呈现的证书时,它需要为ip地址包含san(使用者备用名称)条目。
更改您在客户端中使用的代理url,以使用代理的san或cn字段中已有的内容。
告诉你的应用程序不要验证远程代理证书。这是通过修改socketfactory代码来完成的,您必须包含一个自定义trustmanager,它不会检查主机名/ip是否与证书匹配。
选项1/2可能是最简单的(假设您创建了代理使用的证书),选项3是危险的,因为您不希望此代码滑出到生产环境中,因为它会使某些人更容易进行中间人攻击

wqlqzqxt

wqlqzqxt2#

服务器证书的san字段中似乎缺少ip。如果在san字段中用ip重新创建服务器证书,它应该可以工作。有关类似的问题/答案及解释,请参见此处:的证书与任何主题替代名称都不匹配也许您可以从主机名(而不是ip)调用服务器,但主机名应作为san字段中的dns属性提供

相关问题