Package freenet.crypt

Source Code of freenet.crypt.SSL

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package freenet.crypt;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Key;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;

import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;

import freenet.config.InvalidConfigValueException;
import freenet.config.SubConfig;
import freenet.support.Logger;
import freenet.support.api.BooleanCallback;
import freenet.support.api.StringCallback;
import freenet.support.io.Closer;
import java.net.ServerSocket;

public class SSL {

  private static volatile boolean enable;
  private static KeyStore keystore;
  private static ServerSocketFactory ssf;
  private static String keyStore;
  private static String keyStorePass;
  private static String keyPass;

  /**
   * Call this function before ask ServerSocket
   * @return True is ssl is available
   */
  public static boolean available() {
    return (ssf != null);
  }

  /**
   * Configure SSL support
   * @param sslConfig
   */
  public static void init(SubConfig sslConfig) {
    int configItemOrder = 0;

    // Tracks config parameters related to a SSL
    sslConfig.register("sslEnable", false, configItemOrder++, true, true, "SSL.enable", "SSL.enableLong",
      new BooleanCallback() {

        @Override
        public Boolean get() {
          return enable;
        }

        @Override
        public void set(Boolean newValue) throws InvalidConfigValueException {
          if (!get().equals(newValue)) {
            enable = newValue;
            if(enable)
              try {
                loadKeyStore();
                createSSLContext();
              } catch(Exception e) {
                enable = false;
                e.printStackTrace(System.out);
                throw new InvalidConfigValueException("Cannot enabled ssl, config error");
              }
            else {
              ssf = null;
              keyStore = null;
            }
          }
        }
      });

    sslConfig.register("sslKeyStore", "datastore/certs", configItemOrder++, true, true, "SSL.keyStore", "SSL.keyStoreLong",
      new StringCallback() {

        @Override
        public String get() {
          return keyStore;
        }

        @Override
        public void set(String newKeyStore) throws InvalidConfigValueException {
          if(!newKeyStore.equals(get())) {
            String oldKeyStore = keyStore;
            keyStore = newKeyStore;
            try {
              loadKeyStore();
            } catch(Exception e) {
              keyStore = oldKeyStore;
              e.printStackTrace(System.out);
              throw new InvalidConfigValueException("Cannot change keystore file");
            }
          }
        }
      });

    sslConfig.register("sslKeyStorePass", "freenet", configItemOrder++, true, true, "SSL.keyStorePass", "SSL.keyStorePassLong",
      new StringCallback() {

        @Override
        public String get() {
          return keyStorePass;
        }

        @Override
        public void set(String newKeyStorePass) throws InvalidConfigValueException {
          if(!newKeyStorePass.equals(get())) {
            String oldKeyStorePass = keyStorePass;
            keyStorePass = newKeyStorePass;
            try {
              storeKeyStore();
            } catch(Exception e) {
              keyStorePass = oldKeyStorePass;
              e.printStackTrace(System.out);
              throw new InvalidConfigValueException("Cannot change keystore password");
            }
          }
        }
      });

    sslConfig.register("sslKeyPass", "freenet", configItemOrder++, true, true, "SSL.keyPass", "SSL.keyPassLong",
      new StringCallback() {

        @Override
        public String get() {
          return keyPass;
        }

        @Override
        public void set(String newKeyPass) throws InvalidConfigValueException {
          if(!newKeyPass.equals(get())) {
            String oldKeyPass = keyPass;
            keyPass = newKeyPass;
            try {
              Certificate[] chain = keystore.getCertificateChain("freenet");
              Key privKey = keystore.getKey("freenet", oldKeyPass.toCharArray());
              keystore.setKeyEntry("freenet", privKey, keyPass.toCharArray(), chain);
              createSSLContext();
            } catch(Exception e) {
              keyPass = oldKeyPass;
              e.printStackTrace(System.out);
              throw new InvalidConfigValueException("Cannot change private key password");
            }
          }
        }
      });

    enable = sslConfig.getBoolean("sslEnable");
    keyStore = sslConfig.getString("sslKeyStore");
    keyStorePass = sslConfig.getString("sslKeyStorePass");
    keyPass = sslConfig.getString("sslKeyPass");

    try {
      keystore = KeyStore.getInstance("PKCS12");
      loadKeyStore();
      createSSLContext();
    } catch(Exception e) {
      Logger.error(SSL.class, "Cannot load keystore, ssl is disable", e);
    }
    sslConfig.finishedInitialization();

  }

  /**
   * Create ServerSocket with ssl support
   * @return ServerSocket with ssl support
   * @throws IOException
   */
  public static ServerSocket createServerSocket() throws IOException {
    if(ssf == null)
      throw new IOException("SSL not initialized");
    return ssf.createServerSocket();
  }

  private static void loadKeyStore() throws NoSuchAlgorithmException, CertificateException, IOException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, KeyStoreException, UnrecoverableKeyException, KeyManagementException {
    if(enable) {
      // A keystore is where keys and certificates are kept
      // Both the keystore and individual private keys should be password protected
      FileInputStream fis = null;
      try {
        fis = new FileInputStream(keyStore);
        keystore.load(fis, keyStorePass.toCharArray());
      } catch(FileNotFoundException fnfe) {
        // If keystore not exist, create keystore and server certificate
        keystore.load(null, keyStorePass.toCharArray());
        try {
          Class<?> certAndKeyGenClazz = Class.forName("sun.security.x509.CertAndKeyGen");
          Constructor<?> certAndKeyGenCtor = certAndKeyGenClazz.getConstructor(String.class, String.class);
          Object keypair = certAndKeyGenCtor.newInstance("RSA", "SHA1WithRSA");

          Class<?> x500NameClazz = Class.forName("sun.security.x509.X500Name");
          Constructor<?> x500NameCtor = x500NameClazz.getConstructor(String.class, String.class,
                  String.class, String.class, String.class, String.class);
          Object x500Name = x500NameCtor.newInstance("Freenet", "Freenet", "Freenet", "", "", "");
         
          Method certAndKeyGenGenerate = certAndKeyGenClazz.getMethod("generate", int.class);
          certAndKeyGenGenerate.invoke(keypair, 2048);
         
          Method certAndKeyGetPrivateKey = certAndKeyGenClazz.getMethod("getPrivateKey");
          PrivateKey privKey = (PrivateKey) certAndKeyGetPrivateKey.invoke(keypair);

          Certificate[] chain = new Certificate[1];
          Method certAndKeyGenGetSelfCertificate = certAndKeyGenClazz.getMethod("getSelfCertificate",
                  x500NameClazz, long.class);
          chain[0] = (Certificate) certAndKeyGenGetSelfCertificate.invoke(keypair, x500Name, 1L * 365 * 24
                  * 60 * 60);

          keystore.setKeyEntry("freenet", privKey, keyPass.toCharArray(), chain);
          storeKeyStore();
          createSSLContext();
        } catch (ClassNotFoundException cnfe) {
          throw new UnsupportedOperationException("The JVM you are using is not supported!", cnfe);
        } catch (NoSuchMethodException nsme) {
          throw new UnsupportedOperationException("The JVM you are using is not supported!", nsme);
        }
      } finally {
        Closer.close(fis);
      }
    }
  }

  private static void storeKeyStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
    if(enable) {
      FileOutputStream fos = null;
      try {
        fos = new FileOutputStream(keyStore);
        keystore.store(fos, keyStorePass.toCharArray());
      } finally {
        Closer.close(fos);
      }
    }
  }

  private static void createSSLContext() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, KeyManagementException {
    if(enable) {
      // A KeyManagerFactory is used to create key managers
      KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
      // Initialize the KeyManagerFactory to work with our keystore
      kmf.init(keystore, keyPass.toCharArray());
      // An SSLContext is an environment for implementing JSSE
      // It is used to create a ServerSocketFactory
      SSLContext sslc = SSLContext.getInstance("TLSv1");
      // Initialize the SSLContext to work with our key managers
      // FIXME: should we pass yarrow in here?
      sslc.init(kmf.getKeyManagers(), null, null);
      ssf = sslc.getServerSocketFactory();
    }
  }
}
TOP

Related Classes of freenet.crypt.SSL

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.