diff --git a/src/main/example/SSLServerLetsEncryptExample.java b/src/main/example/SSLServerLetsEncryptExample.java new file mode 100644 index 000000000..f2eb84dc2 --- /dev/null +++ b/src/main/example/SSLServerLetsEncryptExample.java @@ -0,0 +1,108 @@ +import org.java_websocket.WebSocketImpl; +import org.java_websocket.server.DefaultSSLWebSocketServerFactory; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.xml.bind.DatatypeConverter; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; + + +/** + * SSL Example using the LetsEncrypt certificate + * See https://github.com/TooTallNate/Java-WebSocket/wiki/Getting-a-SSLContext-from-different-sources#getting-a-sslcontext-using-a-lets-encrypt-certificate + */ +public class SSLServerLetsEncryptExample { + + public static void main( String[] args ) throws Exception { + WebSocketImpl.DEBUG = true; + + ChatServer chatserver = new ChatServer( 8887 ); + + SSLContext context = getContext(); + if( context != null ) { + chatserver.setWebSocketFactory( new DefaultSSLWebSocketServerFactory( getContext() ) ); + } + chatserver.setConnectionLostTimeout( 30 ); + chatserver.start(); + + } + + private static SSLContext getContext() { + SSLContext context; + String password = "CHANGEIT"; + String pathname = "pem"; + try { + context = SSLContext.getInstance( "TLS" ); + + byte[] certBytes = parseDERFromPEM( getBytes( new File( pathname + File.separator + "cert.pem" ) ), "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----" ); + byte[] keyBytes = parseDERFromPEM( getBytes( new File( pathname + File.separator + "privkey.pem" ) ), "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----" ); + + X509Certificate cert = generateCertificateFromDER( certBytes ); + RSAPrivateKey key = generatePrivateKeyFromDER( keyBytes ); + + KeyStore keystore = KeyStore.getInstance( "JKS" ); + keystore.load( null ); + keystore.setCertificateEntry( "cert-alias", cert ); + keystore.setKeyEntry( "key-alias", key, password.toCharArray(), new Certificate[]{ cert } ); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance( "SunX509" ); + kmf.init( keystore, password.toCharArray() ); + + KeyManager[] km = kmf.getKeyManagers(); + + context.init( km, null, null ); + } catch ( Exception e ) { + context = null; + } + return context; + } + + private static byte[] parseDERFromPEM( byte[] pem, String beginDelimiter, String endDelimiter ) { + String data = new String( pem ); + String[] tokens = data.split( beginDelimiter ); + tokens = tokens[1].split( endDelimiter ); + return DatatypeConverter.parseBase64Binary( tokens[0] ); + } + + private static RSAPrivateKey generatePrivateKeyFromDER( byte[] keyBytes ) throws InvalidKeySpecException, NoSuchAlgorithmException { + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec( keyBytes ); + + KeyFactory factory = KeyFactory.getInstance( "RSA" ); + + return ( RSAPrivateKey ) factory.generatePrivate( spec ); + } + + private static X509Certificate generateCertificateFromDER( byte[] certBytes ) throws CertificateException { + CertificateFactory factory = CertificateFactory.getInstance( "X.509" ); + + return ( X509Certificate ) factory.generateCertificate( new ByteArrayInputStream( certBytes ) ); + } + + private static byte[] getBytes( File file ) { + byte[] bytesArray = new byte[( int ) file.length()]; + + FileInputStream fis = null; + try { + fis = new FileInputStream( file ); + fis.read( bytesArray ); //read file into bytes[] + fis.close(); + } catch ( IOException e ) { + e.printStackTrace(); + } + return bytesArray; + } +}