使用Android和自签名证书

时间:2017-04-28 11:15:29

标签: android ssl self-signed

我在使用自签名证书时遇到问题。我面临例外 java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

我将用几句话来描述我的背景:

我正在使用在Raspberry Pi上运行的NodeJS提供的REST服务开发Android应用程序。对于连接,我想使用SSL / TLS来保护连接,即使这个应用程序也只能在本地网络中使用。

所以我的问题是,我无法使用Lets Encrypt来创建证书,因为没有要验证的域,对吧?我的服务器仅在本地运行,没有要验证的域。 因此,我为自己签名的服务器创建了自签名证书。它工作正常,我将证书添加到我的macOS钥匙串,并且连接是安全的。 对于Android,我使用此approach来验证我的自签名证书,但它无效。我通过原始资源包含了服务器的证书。我认为这可能是问题,我必须将歌唱密钥的公钥包含到信任管理器中,而不是服务器证书本身,对吧? 这说我必须创建一个自己的CA?据我所知:我创建一个RSA密钥对并使用私钥签署证书,我的公钥需要包含在TrustManager中,对吗?

我希望有人可以帮助我:)。

编辑: 我获取SSLContext和getStringFromInputStream()的方法正在按预期工作。

public static SSLContext getSslContext(Context context) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, KeyManagementException, NoSuchProviderException {
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", "BC");
    InputStream inputStream = context.getResources().openRawResource(R.raw.keystore);

    Certificate certificate;

    try {
        certificate = certificateFactory.generateCertificate(inputStream);
    } finally {
        inputStream.close();
    }

    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", certificate);

    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm);
    trustManagerFactory.init(keyStore);

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

    return sslContext;
}

AsyncTask打开连接

public class RestRetrieveTask extends AsyncTask<String, Void, String> 
{
    private Context context;

    public RestRetrieveTask(Context context) {
        this.context = context;
    }

    @Override
    protected String doInBackground(String... strings) {
        String result = null;

        try {
            SSLContext sslContext = CustomSslCertificateAuthority.getSslContext(context);

            URL url = new URL(strings[0]);
            HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
            httpsURLConnection.setSSLSocketFactory(sslContext.getSocketFactory());

            InputStream in = httpsURLConnection.getInputStream();
            result = getStringFromInputStream(in);
            in.close();
        } catch (Exception ex) {
            System.err.println(ex.getMessage());
        }

        return result;
    }

    @Override
    protected void onPostExecute(String s) {
        System.out.println(s);
    }
}

1 个答案:

答案 0 :(得分:0)

我通过创建自己的CA并将根证书的公钥添加到密钥库来解决了这个问题。 它的工作就像一个魅力,我只需要创建自己的HostnameVerifier,因为我没有要验证的主机名。