Я работаю над приложением для Android, для которого требуется аутентификация сертификата клиента и сервера.У меня есть созданный класс SSLClient, который прекрасно работает на обычном настольном компьютере Java SE 6. Я перенес его в свой проект Android и получаю следующую ошибку: «Реализация KeyStore JKS не найдена».
Я немного посмотрел в Интернете, и похоже, что есть вероятность, что Java Keystores не поддерживаются на Android (круто!), Но у меня есть чувство, что это нечто большее, потому что ни один из примеров кода, который я нашел, не похож на то, что япытаюсь сделать вообще.Все, что я нашел, говорит об использовании клиента http, а не сырых сокетов SSL.Мне нужны SSL-сокеты для этого приложения.
Ниже приведен код в моем файле SSLClient.java.Он считывает хранилище ключей и хранилище доверенных сертификатов, создает соединение сокета SSL с сервером, затем запускает цикл, ожидая входные строки от сервера, а затем обрабатывает их по мере их поступления, вызывая метод в другом классе.Мне очень интересно услышать от любого, кто имеет опыт работы с SSL-сокетами на платформе Android.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.security.AccessControlException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import otherpackege.OtherClass;
import android.content.Context;
import android.util.Log;
public class SSLClient
{
static SSLContext ssl_ctx;
public SSLClient(Context context)
{
try
{
// Setup truststore
KeyStore trustStore = KeyStore.getInstance("BKS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
InputStream trustStoreStream = context.getResources().openRawResource(R.raw.mysrvtruststore);
trustStore.load(trustStoreStream, "testtest".toCharArray());
trustManagerFactory.init(trustStore);
// Setup keystore
KeyStore keyStore = KeyStore.getInstance("BKS");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
InputStream keyStoreStream = context.getResources().openRawResource(R.raw.clientkeystore);
keyStore.load(keyStoreStream, "testtest".toCharArray());
keyManagerFactory.init(keyStore, "testtest".toCharArray());
Log.d("SSL", "Key " + keyStore.size());
Log.d("SSL", "Trust " + trustStore.size());
// Setup the SSL context to use the truststore and keystore
ssl_ctx = SSLContext.getInstance("TLS");
ssl_ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
Log.d("SSL", "keyManagerFactory " + keyManagerFactory.getKeyManagers().length);
Log.d("SSL", "trustManagerFactory " + trustManagerFactory.getTrustManagers().length);
}
catch (NoSuchAlgorithmException nsae)
{
Log.d("SSL", nsae.getMessage());
}
catch (KeyStoreException kse)
{
Log.d("SSL", kse.getMessage());
}
catch (IOException ioe)
{
Log.d("SSL", ioe.getMessage());
}
catch (CertificateException ce)
{
Log.d("SSL", ce.getMessage());
}
catch (KeyManagementException kme)
{
Log.d("SSL", kme.getMessage());
}
catch(AccessControlException ace)
{
Log.d("SSL", ace.getMessage());
}
catch(UnrecoverableKeyException uke)
{
Log.d("SSL", uke.getMessage());
}
try
{
Handler handler = new Handler();
handler.start();
}
catch (IOException ioException)
{
ioException.printStackTrace();
}
}
}
//class Handler implements Runnable
class Handler extends Thread
{
private SSLSocket socket;
private BufferedReader input;
static public PrintWriter output;
private String serverUrl = "174.61.103.206";
private String serverPort = "6000";
Handler(SSLSocket socket) throws IOException
{
}
Handler() throws IOException
{
}
public void sendMessagameInfoge(String message)
{
Handler.output.println(message);
}
@Override
public void run()
{
String line;
try
{
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLClient.ssl_ctx.getSocketFactory();
socket = (SSLSocket) socketFactory.createSocket(serverUrl, Integer.parseInt(serverPort));
this.input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Handler.output = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
Log.d("SSL", "Created the socket, input, and output!!");
do
{
line = input.readLine();
while (line == null)
{
line = input.readLine();
}
// Parse the message and do something with it
// Done in a different class
OtherClass.parseMessageString(line);
}
while ( !line.equals("exit|") );
}
catch (IOException ioe)
{
System.out.println(ioe);
}
finally
{
try
{
input.close();
output.close();
socket.close();
}
catch(IOException ioe)
{
}
finally
{
}
}
}
}
Обновление:
Достигнут некоторый хороший прогресс в этой проблеме,Выяснилось, что JKS действительно не поддерживается, и напрямую не выбирает тип SunX509.Я обновил мой код выше, чтобы отразить эти изменения.У меня все еще есть проблема с этим, очевидно, не загружается хранилище ключей и хранилище доверенных сертификатов.Я буду обновляться по мере того, как узнаю больше.
Update2:
Я выполнял загрузку файлов хранилища ключей и доверенных сертификатов в настольном стиле Java, а не в правильном способе Android,Файлы должны быть помещены в папку res / raw и загружены с помощью getResources ().Теперь я получаю счет 1 и 1 для размера хранилища ключей и доверенных сертификатов, что означает, что они загружаются.Я до сих пор разбиваюсь об исключении, но все ближе!Я обновлю, когда у меня получится.
Update3:
Похоже, что все работает сейчас, за исключением того, что мое хранилище ключей настроено неправильно.Если я отключаю аутентификацию на стороне клиента на сервере, он подключается без проблем.Когда я оставляю его включенным, я получаю ошибку handling exception: javax.net.ssl.SSLHandshakeException: null cert chain
.Похоже, я неправильно настраиваю цепочку сертификатов.Я опубликовал еще один вопрос, спрашивающий, как создать клиентское хранилище ключей в формате BKS с правильной цепочкой сертификатов: Как создать хранилище ключей Java в формате BKS (BouncyCastle), которое содержит цепочку клиентских сертификатов