package org.jivesoftware.smack.util;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SmackException;

public class TLSUtils {
   public static final String SSL = "SSL";
   public static final String TLS = "TLS";
   public static final String PROTO_SSL3 = "SSLv3";
   public static final String PROTO_TLSV1 = "TLSv1";
   public static final String PROTO_TLSV1_1 = "TLSv1.1";
   public static final String PROTO_TLSV1_2 = "TLSv1.2";
   private static final HostnameVerifier DOES_NOT_VERIFY_VERIFIER = new HostnameVerifier() {
      public boolean verify(String hostname, SSLSession session) {
         return true;
      }
   };

   public static <B extends ConnectionConfiguration.Builder<B, ?>> B setTLSOnly(B builder) {
      builder.setEnabledSSLProtocols(new String[]{"TLSv1.2", "TLSv1.1", "TLSv1"});
      return builder;
   }

   public static <B extends ConnectionConfiguration.Builder<B, ?>> B setSSLv3AndTLSOnly(B builder) {
      builder.setEnabledSSLProtocols(new String[]{"TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3"});
      return builder;
   }

   public static <B extends ConnectionConfiguration.Builder<B, ?>> B acceptAllCertificates(B builder) throws NoSuchAlgorithmException, KeyManagementException {
      SSLContext context = SSLContext.getInstance("TLS");
      context.init((KeyManager[])null, new TrustManager[]{new TLSUtils.AcceptAllTrustManager()}, new SecureRandom());
      builder.setCustomSSLContext(context);
      return builder;
   }

   public static <B extends ConnectionConfiguration.Builder<B, ?>> B disableHostnameVerificationForTlsCertificicates(B builder) {
      builder.setHostnameVerifier(DOES_NOT_VERIFY_VERIFIER);
      return builder;
   }

   public static void setEnabledProtocolsAndCiphers(SSLSocket sslSocket, String[] enabledProtocols, String[] enabledCiphers) throws SmackException.SecurityNotPossibleException {
      HashSet enabledCiphersSet;
      HashSet supportedCiphersSet;
      HashSet ciphersIntersection;
      if (enabledProtocols != null) {
         enabledCiphersSet = new HashSet(Arrays.asList(enabledProtocols));
         supportedCiphersSet = new HashSet(Arrays.asList(sslSocket.getSupportedProtocols()));
         ciphersIntersection = new HashSet(supportedCiphersSet);
         ciphersIntersection.retainAll(enabledCiphersSet);
         if (ciphersIntersection.isEmpty()) {
            throw new SmackException.SecurityNotPossibleException("Request to enable SSL/TLS protocols '" + StringUtils.collectionToString(enabledCiphersSet) + "', but only '" + StringUtils.collectionToString(supportedCiphersSet) + "' are supported.");
         }

         enabledProtocols = new String[ciphersIntersection.size()];
         enabledProtocols = (String[])ciphersIntersection.toArray(enabledProtocols);
         sslSocket.setEnabledProtocols(enabledProtocols);
      }

      if (enabledCiphers != null) {
         enabledCiphersSet = new HashSet(Arrays.asList(enabledCiphers));
         supportedCiphersSet = new HashSet(Arrays.asList(sslSocket.getEnabledCipherSuites()));
         ciphersIntersection = new HashSet(supportedCiphersSet);
         ciphersIntersection.retainAll(enabledCiphersSet);
         if (ciphersIntersection.isEmpty()) {
            throw new SmackException.SecurityNotPossibleException("Request to enable SSL/TLS ciphers '" + StringUtils.collectionToString(enabledCiphersSet) + "', but only '" + StringUtils.collectionToString(supportedCiphersSet) + "' are supported.");
         }

         enabledCiphers = new String[ciphersIntersection.size()];
         enabledCiphers = (String[])ciphersIntersection.toArray(enabledCiphers);
         sslSocket.setEnabledCipherSuites(enabledCiphers);
      }

   }

   public static class AcceptAllTrustManager implements X509TrustManager {
      public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
      }

      public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
      }

      public X509Certificate[] getAcceptedIssuers() {
         return new X509Certificate[0];
      }
   }
}
