【问题标题】:How to trust my self signed certificate如何信任我的自签名证书
【发布时间】:2014-06-04 04:19:11
【问题描述】:

我想通过 SSL 连接到我的服务器。因此,我使用以下命令在服务器上生成了证书:

openssl genrsa -out server.pem 2048
openssl req -new -x509 -nodes -sha1 -days 3650 -key server.pem > server.cert

如果我使用这样的 TrustManager 信任客户端上的所有证书,则连接有效:

X509TrustManager tm = new X509TrustManager() {

    @Override
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
    }

    @Override
    public void checkClientTrusted(
            X509Certificate[] certs, String authType) {
    }

    @Override
    public void checkServerTrusted(
            X509Certificate[] certs, String authType) {
    }
};

但我当然不想信任所有证书,而只信任我的证书。我尝试了几个命令来导入证书,例如:

keytool -import -alias ca -file server.cert -keystore cacerts

但我总是得到这个错误:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

我需要做什么才能让它工作?有人可以为不太熟悉 cryto 领域的人解释必要的步骤吗?

编辑: 正如 Donal Fellows 所提议的,我尝试了使用自定义 X509TrustManager 的方法并且它有效。但它也像那样安全吗?如果我只是在“getAcceptedIssuers”方法中返回“null”,它也能正常工作,我不太清楚为什么:

X509TrustManager tm = new X509TrustManager() {

    @Override
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {

        X509Certificate[] trustedCerts = new X509Certificate[1];
        try{
            InputStream inStream = new FileInputStream("server.cert");
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
            inStream.close();
            trustedCerts[0] = cert;
        }catch(Exception e){
            e.printStackTrace();
        }

        return trustedCerts;
    }

    @Override
    public void checkClientTrusted(
            X509Certificate[] certs, String authType) {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain,
            String authType) throws CertificateException {

        boolean match = false;
        try{


            InputStream inStream = new FileInputStream("server.cert");
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
            inStream.close();

            for(X509Certificate c : chain){
                if(c.equals(cert)){
                    match = true;
                }
            }
        }catch(Exception e){
            throw new CertificateException();
        }

        if(!match)
            throw new CertificateException();

    }

};

【问题讨论】:

    标签: java security ssl certificate truststore


    【解决方案1】:

    如果您真的要锁定,您可以通过安装自定义 X509TrustManager 来测试所使用的证书是否等于您认为应该是的证书(你肯定知道;你已经生成了它)。这实际上非常安全,但完全没有操作灵活性;如果服务器受到威胁并且您必须重新生成密钥,则所有客户端也需要更新。

    因为这真的很烦人(并且不能扩展到像 WWW 这样的东西),所以使用信任根更正常。信任根是一个自签名 CA 证书,通常具有很长的生命周期,用于对部署到服务器的工作证书进行签名。 (您可以使用 CA 证书本身,但通常最好保持离线状态,可能在防火保险箱中的可移动媒体上。)然后将 CA 证书放入客户端上的信任库(即仅保存证书的密钥库)并告诉 Java 使用它。

    在实践中,您就快到了。您可能只需要告诉 Java 使用您的 cacerts 信任库。您可以通过设置 correct system property 来做到这一点。

    // Be careful on Windows; this property (unusually!) uses “/” instead of “\”
    System.setProperty("javax.net.ssl.trustStore", "/path/to/cacerts");
    

    【讨论】:

      猜你喜欢
      • 2023-03-11
      • 1970-01-01
      • 2016-09-13
      • 1970-01-01
      • 2018-03-10
      • 2016-11-29
      • 2019-09-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多