В Java Network Programming 4th Edition, глава 10 о безопасном Безопасный сервер. Код можно найти здесь.
Я пытаюсь сделать более простую версию кода. Вот мой код:
try {
SSLContext context = SSLContext.getInstance(algorithm);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
//char[] password = System.console().readPassword("Password: "); // open the .class with command line
char[] password = {'t', 'h', 'i', 's', 'i', 's', 't', 'i', 'a', 'n'};
ks.load(new FileInputStream("src/jnp4e.keys"), password);
kmf.init(ks, password);
context.init(kmf.getKeyManagers(), null, null); // null = accept the default
// wipe the password
Arrays.fill(password, '0');
SSLServerSocketFactory factory
= context.getServerSocketFactory();
SSLServerSocket server
= (SSLServerSocket) factory.createServerSocket(PORT);
// add anonymous (non-authenticated) cipher suites
String[] supported = server.getSupportedCipherSuites();
String[] anonCipherSuitesSupported = new String[supported.length];
int numAnonCipherSuitesSupported = 0;
for (int i = 0; i < supported.length; i++) {
if (supported[i].indexOf("_anon_") > 0) {
anonCipherSuitesSupported[numAnonCipherSuitesSupported++]
= supported[i];
}
}
String[] oldEnabled = server.getEnabledCipherSuites();
String[] newEnabled = new String[oldEnabled.length
+ numAnonCipherSuitesSupported];
System.arraycopy(oldEnabled, 0, newEnabled, 0, oldEnabled.length);
System.arraycopy(anonCipherSuitesSupported, 0, newEnabled,
oldEnabled.length, numAnonCipherSuitesSupported);
server.setEnabledCipherSuites(newEnabled);
System.out.println("OK..");
// Now all the set up is complete and we can focus
// on the actual communication.
while (true) {
// This socket will be secure,
// but there's no indication of that in the code!
try (Socket theConnection = server.accept()) {
InputStream in = theConnection.getInputStream();
Reader r = new InputStreamReader(in, "UTF-8");
int c;
while ((c = r.read()) != -1) {
System.out.write(c);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
} catch (IOException | KeyManagementException | KeyStoreException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException ex) {
ex.printStackTrace();
}
Единственная разница в том, что в моем коде я создаю Reader
, чтобы сервер мог читать символы. Я попробовал этот сервер с простым клиентом, который отправляет текст. Вот Клиент:
int port = 7000; // default https port
String host = "localhost";
SSLSocketFactory factory
= (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = null;
try {
socket = (SSLSocket) factory.createSocket(host, port);
// enable all the suites
String[] supported = socket.getSupportedCipherSuites();
socket.setEnabledCipherSuites(supported);
Writer out = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");
out.write("Hello");
}catch(Exception e){
}
Сначала я запускаю сервер, а затем Cient. Но когда сервер принимает ввод от клиента, он выдает это исключение:
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:189)
at java.net.SocketInputStream.read(SocketInputStream.java:121)
...
ОБНОВЛЕНИЕ КЛИЕНТА Основываясь на ответе Дейва, я добавляю 2 строки кода flush()
и close()
...
out.write("Hello");
out.flush();
socket.close();
...
Но приходит другое исключение:
javax.net.ssl.SSLHandshakeException: Received fatal alert: certificate_unknown