簡體   English   中英

如何信任我的自簽名證書

[英]How to trust my self signed certificate

我想通過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();

    }

};

如果您確實要限制一切,則可以通過安裝自定義X509TrustManager進行測試,該測試將測試所使用的證書是否等於您認為應該的證書(您肯定知道;已經生成了該證書)。 這實際上是相當安全的,但是完全沒有操作靈活性。 如果服務器受到威脅,並且您必須重新生成密鑰,則所有客戶端也將需要更新。

因為這確實很煩人(並且無法擴展到WWW之類的功能),所以使用信任根更為正常。 信任根是一個自簽名的CA證書,通常具有很長的壽命,用於對部署到服務器的工作證書進行簽名。 (您可以使用CA證書本身,但通常最好將其保持脫機狀態,最好將其保存在防火安全的可移動媒體上。)然后,將CA證書放入客戶端上的信任庫(即僅保存證書的密鑰庫)中。並告訴Java使用它。

在實踐中,您快到了。 您可能只需要告訴Java使用cacerts信任庫即可。 您可以通過設置正確的系統屬性來實現

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM