PlainServer.java that doesn’t verify client
In previous example, we have a client and server pair that do mutual certification. I saw some comments and questions in stack overflow about this setup. In many situations, server don’t care about the client side is legitimate or not, server can skip verifying the client’s public key.
- step 1. Create self-signed server and client certificates with keytool.
- step 2. create server java code.
- step 3. create client java code.
SSLDemo #mkdir ssldemo SSLDemo #cd ssldemo/ SSLDemo #echo "Generate the Client and Server Keystores" > /dev/null SSLDemo #keytool -genkeypair -alias plainserverkeys -keyalg RSA -dname "CN=Plain Server,OU=kl2217,O=kl2217org,L=Boston,ST=MA,C=US" -keypass password -keystore plainserver.jks -storepass password SSLDemo #keytool -genkeypair -alias plainclientkeys -keyalg RSA -dname "CN=Plain Client,OU=kl2217,O=kl2217org,L=Boston,ST=MA,C=US" -keypass password -keystore plainclient.jks -storepass password SSLDemo #echo "Export the server public certificate and create a seperate keystore">/dev/null SSLDemo #keytool -exportcert -alias plainserverkeys -file serverpub.cer -keystore plainserver.jks -storepass password Certificate stored in file SSLDemo #keytool -importcert -keystore serverpub.jks -alias serverpub -file serverpub.cer -storepass password Owner: CN=Plain Server, OU=kl2217, O=kl2217org, L=Boston, ST=MA, C=US Issuer: CN=Plain Server, OU=kl2217, O=kl2217org, L=Boston, ST=MA, C=US Serial number: 23430928 Valid from: Fri Dec 27 11:48:10 EST 2019 until: Thu Mar 26 12:48:10 EDT 2020 Certificate fingerprints: MD5: 41:CB:3E:75:BC:74:45:3F:09:E2:43:82:99:DD:60:62 SHA1: DF:96:E4:A2:CF:70:17:AE:85:71:E3:94:F7:4E:95:00:4A:B1:C4:E1 SHA256: A7:4E:45:65:C5:6F:8E:38:91:F5:04:39:0F:F8:6A:98:CA:E4:F9:19:1E:66:F9:FB:B5:DD:52:90:9A:12:C4:97 Signature algorithm name: SHA256withRSA Version: 3 Extensions: #1: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: 2E 36 E1 D0 AF CF 28 4D 41 1D DC 64 27 8A 44 98 .6....(MA..d'.D. 0010: F6 61 35 CB .a5. ] ] Trust this certificate? [no]: yes Certificate was added to keystore SSLDemo #ls plainclient.jks plainserver.jks serverpub.cer serverpub.jks SSLDemo #vi PlainServer.java SSLDemo #vi PlainClient.java SSLDemo #cat PlainClient.java import java.io.*; import java.security.*; import javax.net.ssl.*; public class PlainClient { public static void main(String[] args) { SSLSocket socket = null; BufferedReader in = null; try { // load client private key KeyStore clientKeys = KeyStore.getInstance("JKS"); clientKeys.load(new FileInputStream("plainclient.jks"), "password".toCharArray()); //a jks containing any valid private key will work KeyManagerFactory clientKeyManager = KeyManagerFactory .getInstance("SunX509"); clientKeyManager.init(clientKeys, "password".toCharArray()); // load server public key KeyStore serverPub = KeyStore.getInstance("JKS"); serverPub.load(new FileInputStream("serverpub.jks"), "password".toCharArray()); TrustManagerFactory trustManager = TrustManagerFactory .getInstance("SunX509"); trustManager.init(serverPub); // use keys to create SSLSoket SSLContext ssl = SSLContext.getInstance("TLS"); ssl.init(clientKeyManager.getKeyManagers(), trustManager.getTrustManagers(), SecureRandom.getInstance("SHA1PRNG")); socket = (SSLSocket) ssl.getSocketFactory().createSocket( "localhost", 8889); socket.startHandshake(); // receive data in = new BufferedReader(new InputStreamReader( socket.getInputStream())); String data; while ((data = in.readLine()) != null) { System.out.println(data); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (in != null) in.close(); if (socket != null) socket.close(); if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } SSLDemo # SSLDemo #cat PlainServer.java import java.io.*; import java.security.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.*; public class PlainServer { public static void main(String[] args) { SSLServerSocket serverSock = null; SSLSocket socket = null; PrintWriter out = null; try { // load server private key KeyStore serverKeys = KeyStore.getInstance("JKS"); serverKeys.load(new FileInputStream( "plainserver.jks"), "password" .toCharArray()); KeyManagerFactory serverKeyManager = KeyManagerFactory .getInstance("SunX509"); // System.out.println(KeyManagerFactory.getDefaultAlgorithm()); // System.out.println(serverKeyManager.getProvider()); serverKeyManager.init(serverKeys, "password".toCharArray()); // load client public key is not needed TrustManager[] trustManagers = new X509TrustManager[] { new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } } }; // use keys to create SSLSoket SSLContext ssl = SSLContext.getInstance("TLS"); ssl.init(serverKeyManager.getKeyManagers(), trustManagers, SecureRandom.getInstance("SHA1PRNG")); serverSock = (SSLServerSocket) ssl.getServerSocketFactory() .createServerSocket(8889); serverSock.setNeedClientAuth(true); socket = (SSLSocket) serverSock.accept(); // send data out = new PrintWriter(new BufferedWriter(new OutputStreamWriter( socket.getOutputStream()))); out.println("data from PlainServer"); out.flush(); } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("exit"); if (out != null) out.close(); try { if (serverSock != null) serverSock.close(); if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } SSLDemo # SSLDemo # SSLDemo #javac PlainServer.java PlainClient.java SSLDemo #java PlainServer & [1] 4227 SSLDemo #java PlainClient exit data from PlainServer [1]+ Done java PlainServer SSLDemo #
in case bad serverpub.jks is supplied by PlainClient.java, the exception will be:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1937)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1478)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:957)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:892)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1050)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
at misc.PlainClient.main(PlainClient.java:33)
Caused by: sun.security.validator.ValidatorException: No trusted certificate found
at sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:384)
at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:133)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1460)
… 8 more
kl2217
December 27, 2019