package com.xjeffrose.xio.tls;

import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManagerFactory;

public class SslContextFactory {

  private static SslContextBuilder configure(TlsConfig config, SslContextBuilder builder) {
    return builder
        .applicationProtocolConfig(config.getAlpnConfig())
        .ciphers(config.getCiphers(), SupportedCipherSuiteFilter.INSTANCE)
        .clientAuth(config.getClientAuth())
        .enableOcsp(config.isEnableOcsp())
        .protocols(config.getProtocols())
        .sessionCacheSize(config.getSessionCacheSize())
        .sessionTimeout(config.getSessionTimeout())
        .sslProvider(config.getSslProvider());
  }

  private static SslContextBuilder newServerBuilder(TlsConfig config) {
    return SslContextBuilder.forServer(config.getPrivateKey(), config.getCertificateAndChain());
  }

  public static SslContext buildServerContext(TlsConfig config, TrustManagerFactory trustManager) {
    try {
      return configure(config, newServerBuilder(config))
          .trustManager(new XioTrustManagerFactory(trustManager))
          .build();
    } catch (SSLException e) {
      return null;
    }
  }

  public static SslContext buildServerContext(TlsConfig config) {
    return buildServerContext(config, buildTrustManagerFactory(config.getTrustedCerts()));
  }

  public static SslContext buildClientContext(TlsConfig config, TrustManagerFactory trustManager) {
    try {
      return configure(config, SslContextBuilder.forClient())
          .keyManager(config.getPrivateKey(), config.getCertificateAndChain())
          .trustManager(new XioTrustManagerFactory(trustManager))
          .build();
    } catch (SSLException e) {
      return null;
    }
  }

  static TrustManagerFactory buildTrustManagerFactory(X509Certificate[] certCollection) {
    try {
      KeyStore ks = KeyStore.getInstance("JKS");
      ks.load(null, null);

      int i = 1;
      for (X509Certificate cert : certCollection) {
        String alias = Integer.toString(i);
        ks.setCertificateEntry(alias, cert);
        i++;
      }

      TrustManagerFactory trustManagerFactory =
          TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

      trustManagerFactory.init(ks);

      return trustManagerFactory;
    } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | IOException e) {
      return null;
    }
  }

  public static SslContext buildClientContext(TlsConfig config) {
    // clients will trust only certs in trusted certs collection
    return buildClientContext(config, buildTrustManagerFactory(config.getTrustedCerts()));
  }
}

@@ -25,16 +25,56 @@
 o.tls;%0A%0A
+import io.netty.handler.ssl.ClientAuth;%0A
 import i
@@ -445,16 +445,50 @@
 ficate;%0A
+import javax.annotation.Nullable;%0A
 import j
@@ -1403,34 +1403,269 @@
 ) %7B%0A    
-try %7B%0A      return
+return buildServerContext(config, trustManager, null);%0A  %7D%0A%0A  public static SslContext buildServerContext(%0A      TlsConfig config, TrustManagerFactory trustManager, @Nullable ClientAuth clientAuth) %7B%0A    try %7B%0A      SslContextBuilder builder =%0A         
  configu
@@ -1701,16 +1701,20 @@
 onfig))%0A
+    
         
@@ -1766,35 +1766,128 @@
 ustManager))
+;%0A
 %0A      
-    
+if (clientAuth != null) %7B%0A        builder.clientAuth(clientAuth);%0A      %7D%0A%0A      return builder
 .build();%0A  
@@ -2099,32 +2099,238 @@
 Certs()));%0A  %7D%0A%0A
+  public static SslContext buildServerContext(TlsConfig config, ClientAuth clientAuth) %7B%0A    return buildServerContext(%0A        config, buildTrustManagerFactory(config.getTrustedCerts()), clientAuth);%0A  %7D%0A%0A
   public static 

add client auth option to ssl context builder (#318)