使用 Android 和自签名证书
Using Android and a self signed certificate
我在 android 中使用自签名证书时遇到问题。我面临例外
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
我会用几句话描述我的背景:
我正在 Raspberry Pi 上使用 NodeJS 运行 提供的 REST 服务开发一个 Android 应用程序。对于连接,我想使用 SSL/TLS 来保护连接,即使这个应用程序也只会在本地网络中使用。
所以我的问题是,我不能使用 Lets Encrypt 来创建证书,因为没有要验证的域,对吧?我的服务器仅是 运行 本地服务器,没有要验证的域。
因此,我为自己签名的服务器创建了一个自签名证书。它工作正常,我将证书添加到我的 macOS 钥匙串并且连接是安全的。
对于 Android,我使用此 approach 来验证我的自签名证书,但它不起作用。我通过原始资源包含了服务器证书。我认为这可能是问题所在,我必须将唱歌密钥的 public 密钥包含到信任管理器中,而不是服务器证书本身,对吧?
这就是说我必须创建一个自己的 CA?据我了解:我创建了一个 RSA 密钥对并使用私钥签署证书,我的 public 密钥需要包含在 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);
}
}
我通过创建自己的 CA 并将根证书的 public 密钥添加到密钥库来解决了这个问题。
它就像一个魅力,我只需要创建我自己的 HostnameVerifier
因为我没有要验证的主机名。
我在 android 中使用自签名证书时遇到问题。我面临例外
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
我会用几句话描述我的背景:
我正在 Raspberry Pi 上使用 NodeJS 运行 提供的 REST 服务开发一个 Android 应用程序。对于连接,我想使用 SSL/TLS 来保护连接,即使这个应用程序也只会在本地网络中使用。
所以我的问题是,我不能使用 Lets Encrypt 来创建证书,因为没有要验证的域,对吧?我的服务器仅是 运行 本地服务器,没有要验证的域。 因此,我为自己签名的服务器创建了一个自签名证书。它工作正常,我将证书添加到我的 macOS 钥匙串并且连接是安全的。 对于 Android,我使用此 approach 来验证我的自签名证书,但它不起作用。我通过原始资源包含了服务器证书。我认为这可能是问题所在,我必须将唱歌密钥的 public 密钥包含到信任管理器中,而不是服务器证书本身,对吧? 这就是说我必须创建一个自己的 CA?据我了解:我创建了一个 RSA 密钥对并使用私钥签署证书,我的 public 密钥需要包含在 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);
}
}
我通过创建自己的 CA 并将根证书的 public 密钥添加到密钥库来解决了这个问题。
它就像一个魅力,我只需要创建我自己的 HostnameVerifier
因为我没有要验证的主机名。