From 38b86b16ded5ce9c8cf7ad4737c39d1ed712dbd9 Mon Sep 17 00:00:00 2001 From: Florian Charlaix Date: Wed, 5 Jan 2022 10:00:07 +0100 Subject: [PATCH] Setup SSL for WebSocket connection --- src/fr/univ/lyon1/client/Client.java | 20 +++++++- src/fr/univ/lyon1/common/ChatSSL.java | 57 +++++++++++++++++++++++ src/fr/univ/lyon1/server/Connection.java | 18 ++++++- src/main/resources/servercert.p12 | Bin 0 -> 1204 bytes 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/fr/univ/lyon1/common/ChatSSL.java create mode 100644 src/main/resources/servercert.p12 diff --git a/src/fr/univ/lyon1/client/Client.java b/src/fr/univ/lyon1/client/Client.java index abb6001..ec650a1 100644 --- a/src/fr/univ/lyon1/client/Client.java +++ b/src/fr/univ/lyon1/client/Client.java @@ -1,12 +1,17 @@ package fr.univ.lyon1.client; import fr.univ.lyon1.common.Channel; +import fr.univ.lyon1.common.ChatSSL; import fr.univ.lyon1.common.Message; import fr.univ.lyon1.common.command.Command; import fr.univ.lyon1.common.command.CommandType; import fr.univ.lyon1.common.exception.ChatException; import fr.univ.lyon1.common.exception.UnknownCommand; +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocket; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -31,11 +36,24 @@ public class Client { this.port = port; this.username = username; this.password = password; - socket = new Socket(address, port); + socket = initSSL(); out = new ObjectOutputStream(socket.getOutputStream()); getIn(); } + private Socket initSSL() throws IOException { + SSLContext ctx = ChatSSL.getSSLContext(); + + SocketFactory factory = ctx.getSocketFactory(); + + Socket connection = factory.createSocket(address, port); + ((SSLSocket) connection).setEnabledProtocols(new String[] {ChatSSL.tlsVersion}); + SSLParameters sslParams = new SSLParameters(); + sslParams.setEndpointIdentificationAlgorithm("HTTPS"); + ((SSLSocket) connection).setSSLParameters(sslParams); + return connection; + } + public void disconnectedServer() throws IOException { socket.close(); out.close(); diff --git a/src/fr/univ/lyon1/common/ChatSSL.java b/src/fr/univ/lyon1/common/ChatSSL.java new file mode 100644 index 0000000..f00b7c1 --- /dev/null +++ b/src/fr/univ/lyon1/common/ChatSSL.java @@ -0,0 +1,57 @@ +package fr.univ.lyon1.common; + +import fr.univ.lyon1.server.Connection; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import java.io.IOException; +import java.io.InputStream; +import java.security.*; +import java.security.cert.CertificateException; + +/* +keytool -genkeypair -alias server -keyalg EC \ +-sigalg SHA384withECDSA -keysize 256 -keystore servercert.p12 \ +-storetype pkcs12 -v -storepass abc123 -validity 10000 -ext san=ip:127.0.0.1 + */ + +public class ChatSSL { + public static String trustStoreName = "servercert.p12"; + public static String keyStoreName = "servercert.p12"; + public static String tlsVersion = "TLSv1.2"; + private static char[] trustStorePassword = "abc123".toCharArray(); + private static char[] keyStorePassword = "abc123".toCharArray(); + + public static SSLContext getSSLContext() { + + try { + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + InputStream tstore = Connection.class + .getResourceAsStream("/" + trustStoreName); + trustStore.load(tstore, trustStorePassword); + tstore.close(); + TrustManagerFactory tmf = TrustManagerFactory + .getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(trustStore); + + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + InputStream kstore = Connection.class + .getResourceAsStream("/" + keyStoreName); + keyStore.load(kstore, keyStorePassword); + KeyManagerFactory kmf = KeyManagerFactory + .getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(keyStore, keyStorePassword); + SSLContext ctx = SSLContext.getInstance("TLS"); + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), + SecureRandom.getInstanceStrong()); + + return ctx; + } catch (KeyStoreException | IOException | NoSuchAlgorithmException | KeyManagementException | CertificateException | UnrecoverableKeyException e) { + e.printStackTrace(); + System.exit(1); + } + + return null; + } +} diff --git a/src/fr/univ/lyon1/server/Connection.java b/src/fr/univ/lyon1/server/Connection.java index 7ab3b09..251f763 100644 --- a/src/fr/univ/lyon1/server/Connection.java +++ b/src/fr/univ/lyon1/server/Connection.java @@ -1,5 +1,8 @@ package fr.univ.lyon1.server; +import fr.univ.lyon1.common.ChatSSL; + +import javax.net.ssl.*; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; @@ -10,7 +13,20 @@ public class Connection implements Runnable { Connection(Server server) throws IOException { this.server = server; - this.serverSocket = new ServerSocket(server.getPort()); + this.serverSocket = initSSL(); + } + + private SSLServerSocket initSSL() throws IOException { + + SSLContext ctx = ChatSSL.getSSLContext(); + + SSLServerSocketFactory factory = ctx.getServerSocketFactory(); + ServerSocket listener = factory.createServerSocket(server.getPort()); + SSLServerSocket sslListener = (SSLServerSocket) listener; + + sslListener.setNeedClientAuth(true); + sslListener.setEnabledProtocols(new String[]{ChatSSL.tlsVersion}); + return sslListener; } public void run() { diff --git a/src/main/resources/servercert.p12 b/src/main/resources/servercert.p12 new file mode 100644 index 0000000000000000000000000000000000000000..19df118305fa21b898f97669169f69329767f5d6 GIT binary patch literal 1204 zcmXqLV%fmN$ZXKW62-=;)#lOmotKfFaX}M{H%k+XJ5bo!povinMT$|HrHN4-C@c)b z{A}D%T|8WjObZ(K8Z_=QNQ0|q!Px@3%g8-nmp%d%g)VfpkFTvdXIBNQL{?!tUiUq&7D+F*Rg3 zZW47?G|zuK-6P#>*|PVQ$(l-jXDsH&b#8C-4A}AY&Y7Pr(xxABG%kMNPg>SnocuX{ z=gV1%dG3*qly3*8@;tUn3H-RwTIS4k#Q>Gwy(=f|D!THsJ>%-%fNTTn`6X=et!M0Z zPpQtodq`@H_;TO$SN-#+*O}=rs!94afxByG>%>Z-+jnC>+I_n6disl*tIQ;ioRDUE z{98M&*R*1PzS*S>iOade*0!CW?Pa|6is?-6C$EGWL+hC)vvDudP3Ny-HyoYCRH*zg*7jpNrckKIrW0&uQ5Y2L? z%gg#1JU4xH{PAhUyuI_4%eH?~^iXjVakBaGX0`E$8$NlHj+8DpSkUyb_LSD{U8$!Y zF+Nc`aNIm>GJCma({7IQaZ$czYXi0(vR?O~b-BjW1*vo1zh8OltJA{Q&tINh>hsBT zj}rTfurMag7m*ut)wZ}Cl)5TX=*@WaWv+tAtY7mVwM`IxwZi_C>*Gz#xm8|z>Tjwx zlqmK0|GRQH^KO!;T+;tLVe8o4rp%7dikUF=w%|^SU+i|X(vP2>`uSj2q_Fp1$(hrO zew6qzzL!7r`a`%~+V_NNwY**B*{eAd+GpjQ-8kFoQOMf0)8wbT$oX8Tdp^nH_3FK8 z^IiXnPKe73c+vjrhREFMZD%Yc`gYkr`}<4!`K%tE??n~v zdF|7ATTai(Et$VOz~IPNm+odR=@`EA{v83XO9L&udg?cadp>k?FIaYbXZEB8qHzYk z28IT_@Vv~#$jZQ?aHvpFvaMv!g-=~e{5Ee9@LiU6?3O9}oLBKVD=)KhXC7e@QMY-< Y{*w7?4VMy&Tb