SSLConfig.java 14 KB
Newer Older
1 2 3 4 5
/**
 * $RCSfile$
 * $Revision: 1217 $
 * $Date: 2005-04-11 18:11:06 -0300 (Mon, 11 Apr 2005) $
 *
6
 * Copyright (C) 2005-2008 Jive Software. All rights reserved.
7 8
 *
 * This software is published under the terms of the GNU Public License (GPL),
9 10
 * a copy of which is included in this distribution, or a commercial license
 * agreement with Jive.
11 12
 */

13
package org.jivesoftware.openfire.net;
14

15 16
import org.jivesoftware.util.CertificateEventListener;
import org.jivesoftware.util.CertificateManager;
17 18 19
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log;

20 21 22 23
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManagerFactory;
24 25 26 27 28 29 30
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.security.KeyStore;
31 32
import java.security.cert.X509Certificate;
import java.util.List;
33 34

/**
35
 * Configuration of Openfire's SSL settings.
36 37 38 39 40
 *
 * @author Iain Shigeoka
 */
public class SSLConfig {

41 42 43 44 45 46 47
    private static SSLServerSocketFactory s2sFactory;
    private static SSLServerSocketFactory c2sFactory;

    private static String storeType;
    private static SSLContext s2sContext;
    private static SSLContext c2sContext;

48 49
    private static KeyStore keyStore;
    private static String keyStoreLocation;
50 51 52 53 54 55 56 57 58 59
    private static String keypass;

    private static KeyStore s2sTrustStore;
    private static String s2sTrustStoreLocation;
    private static String s2sTrustpass;

    private static KeyStore c2sTrustStore;
    private static String c2sTrustStoreLocation;
    private static String c2sTrustpass;

60 61 62 63 64 65

    private SSLConfig() {
    }

    static {
        String algorithm = JiveGlobals.getProperty("xmpp.socket.ssl.algorithm", "TLS");
Alex Wenckus's avatar
Alex Wenckus committed
66
        storeType = JiveGlobals.getProperty("xmpp.socket.ssl.storeType", "jks");
67 68 69 70 71 72 73 74 75 76

        // Get the keystore location. The default location is security/keystore
        keyStoreLocation = JiveGlobals.getProperty("xmpp.socket.ssl.keystore",
                "resources" + File.separator + "security" + File.separator + "keystore");
        keyStoreLocation = JiveGlobals.getHomeDirectory() + File.separator + keyStoreLocation;

        // Get the keystore password. The default password is "changeit".
        keypass = JiveGlobals.getProperty("xmpp.socket.ssl.keypass", "changeit");
        keypass = keypass.trim();

77 78 79 80 81 82 83 84 85 86
        // Get the truststore location for c2s connections
        c2sTrustStoreLocation = JiveGlobals.getProperty("xmpp.socket.ssl.client.truststore",
                "resources" + File.separator + "security" + File.separator + "client.truststore");
        c2sTrustStoreLocation = JiveGlobals.getHomeDirectory() + File.separator + c2sTrustStoreLocation;

        c2sTrustpass = JiveGlobals.getProperty("xmpp.socket.ssl.client.trustpass", "changeit");
        c2sTrustpass = c2sTrustpass.trim();

        // Get the truststore location for s2s connections
        s2sTrustStoreLocation = JiveGlobals.getProperty("xmpp.socket.ssl.truststore",
87
                "resources" + File.separator + "security" + File.separator + "truststore");
88
        s2sTrustStoreLocation = JiveGlobals.getHomeDirectory() + File.separator + s2sTrustStoreLocation;
89 90

        // Get the truststore passwprd; default is "changeit".
91 92
        s2sTrustpass = JiveGlobals.getProperty("xmpp.socket.ssl.trustpass", "changeit");
        s2sTrustpass = s2sTrustpass.trim();
93

94
	    // Load s2s keystore and trusstore
95 96 97 98
        try {
            keyStore = KeyStore.getInstance(storeType);
            keyStore.load(new FileInputStream(keyStoreLocation), keypass.toCharArray());

99 100 101 102
            s2sTrustStore = KeyStore.getInstance(storeType);
            s2sTrustStore.load(new FileInputStream(s2sTrustStoreLocation), s2sTrustpass.toCharArray());


103 104 105 106 107 108
        }
        catch (Exception e) {
            Log.error("SSLConfig startup problem.\n" +
                    "  storeType: [" + storeType + "]\n" +
                    "  keyStoreLocation: [" + keyStoreLocation + "]\n" +
                    "  keypass: [" + keypass + "]\n" +
109 110
                    "  s2sTrustStoreLocation: [" + s2sTrustStoreLocation + "]\n" +
                    "  s2sTrustpass: [" + s2sTrustpass + "]\n"); 
111
            keyStore = null;
112 113
            s2sTrustStore = null;
            s2sFactory = null;
114
        }
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
        // Load c2s trusstore
        try {
            if (s2sTrustStoreLocation.equals(c2sTrustStoreLocation)) {
                c2sTrustStore = s2sTrustStore;
                c2sTrustpass = s2sTrustpass;
            }
            else {
                c2sTrustStore = KeyStore.getInstance(storeType);
                c2sTrustStore.load(new FileInputStream(c2sTrustStoreLocation), c2sTrustpass.toCharArray());
            }
        }
        catch (Exception e) {
            try {
                c2sTrustStore = KeyStore.getInstance(storeType);
                c2sTrustStore.load(null, c2sTrustpass.toCharArray());
            }
            catch (Exception ex) {
                Log.error("SSLConfig startup problem.\n" +
                        "  storeType: [" + storeType + "]\n" +
                        "  c2sTrustStoreLocation: [" + c2sTrustStoreLocation + "]\n" +
                        "  c2sTrustPass: [" + c2sTrustpass + "]", e);
                c2sTrustStore = null;
                c2sFactory = null;
            }
        }
        resetFactory();
141

142 143
        // Reset ssl factoty when certificates are modified
        CertificateManager.addListener(new CertificateEventListener() {
144
            // Reset ssl factory since keystores have changed
145
            public void certificateCreated(KeyStore keyStore, String alias, X509Certificate cert) {
146
                resetFactory();
147
            }
148

149
            public void certificateDeleted(KeyStore keyStore, String alias) {
150
                resetFactory();
151
            }
152

153 154
            public void certificateSigned(KeyStore keyStore, String alias, List<X509Certificate> certificates) {
                resetFactory();
155 156
            }
        });
157 158
    }

159 160 161 162
    private static void resetFactory() {
        try {
            String algorithm = JiveGlobals.getProperty("xmpp.socket.ssl.algorithm", "TLS");

163 164
            s2sContext = SSLContext.getInstance(algorithm);
            c2sContext = SSLContext.getInstance(algorithm);
165 166 167 168

            KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyFactory.init(keyStore, SSLConfig.getKeyPassword().toCharArray());

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
            TrustManagerFactory s2sTrustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            s2sTrustFactory.init(s2sTrustStore);

            s2sContext.init(keyFactory.getKeyManagers(),
                    s2sTrustFactory.getTrustManagers(),
                    new java.security.SecureRandom());

            s2sFactory = s2sContext.getServerSocketFactory();

            if (s2sTrustStore == c2sTrustStore) {
                c2sContext = s2sContext;
                c2sFactory = s2sFactory;
            }
            else {
                TrustManagerFactory c2sTrustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                c2sTrustFactory.init(c2sTrustStore);
185

186
                c2sContext.init(keyFactory.getKeyManagers(),
187
                    c2sTrustFactory.getTrustManagers(),
188 189
                    new java.security.SecureRandom());

190 191 192
                c2sFactory = c2sContext.getServerSocketFactory();
            }

193 194 195 196 197 198
        }
        catch (Exception e) {
            Log.error("SSLConfig factory setup problem.\n" +
                    "  storeType: [" + storeType + "]\n" +
                    "  keyStoreLocation: [" + keyStoreLocation + "]\n" +
                    "  keypass: [" + keypass + "]\n" +
199 200 201 202
                    "  s2sTrustStoreLocation: [" + s2sTrustStoreLocation+ "]\n" +
                    "  s2sTrustpass: [" + s2sTrustpass + "]" +
                    "  c2sTrustStoreLocation: [" + c2sTrustStoreLocation + "]\n" +
                    "  c2sTrustpass: [" + c2sTrustpass + "]", e);
203
            keyStore = null;
204 205 206 207
            s2sTrustStore = null;
            c2sTrustStore = null;
            s2sFactory = null;
            c2sFactory = null;
208 209 210
        }
    }

211 212 213 214 215
    /**
     * Get the Key Store password
     *
     * @return the key store password
     */
216 217 218 219
    public static String getKeyPassword() {
        return keypass;
    }

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
    /**
     * Return the Trust Store password for s2s connections.
     *
     * @return the s2s trust store password.
     */
    public static String gets2sTrustPassword() {
        return s2sTrustpass;
    }


    /**
     * Return the Trust Store password for c2s connections.
     *
     * @return the c2s trust store password.
     */
    public static String getc2sTrustPassword() {
        return c2sTrustpass;
237 238 239 240
    }

    public static String[] getDefaultCipherSuites() {
        String[] suites;
241
        if (s2sFactory == null) {
242 243 244
            suites = new String[]{};
        }
        else {
245
            suites = s2sFactory.getDefaultCipherSuites();
246 247 248 249
        }
        return suites;
    }

250
    public static String[] getSupportedCipherSuites() {
251
        String[] suites;
252
        if (s2sFactory == null) {
253 254 255
            suites = new String[]{};
        }
        else {
256
            suites = s2sFactory.getSupportedCipherSuites();
257 258 259 260
        }
        return suites;
    }

261 262 263 264 265
    /**
     * Get the Key Store
     *
     * @return the Key Store
     */
266 267 268 269 270 271 272
    public static KeyStore getKeyStore() throws IOException {
        if (keyStore == null) {
            throw new IOException();
        }
        return keyStore;
    }

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    /**
     * Get the Trust Store for s2s connections
     *
     * @return the s2s Trust Store
     */
    public static KeyStore gets2sTrustStore() throws IOException {
        if (s2sTrustStore == null) {
            throw new IOException();
        }
        return s2sTrustStore;
    }

    /** 
     * Get the Trust Store for c2s connections
     *
     * @return the c2s Trust Store
     */ 
    public static KeyStore getc2sTrustStore() throws IOException {
        if (c2sTrustStore == null) {
292 293
            throw new IOException();
        }
294
        return c2sTrustStore;
295 296
    }

297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
    /**
     * Initializes (wipes and recreates) the keystore, and returns the new keystore.
     *
     * @return Newly initialized keystore.
     */
    public static KeyStore initializeKeyStore() {
        try {
            keyStore = KeyStore.getInstance(storeType);
            keyStore.load(null, keypass.toCharArray());
        }
        catch (Exception e) {
            Log.error("Unable to initialize keystore: ", e);
        }
        return keyStore;
    }

313 314 315
    /**
     * Save all key and trust stores.
     */
316 317 318
    public static void saveStores() throws IOException {
        try {
            keyStore.store(new FileOutputStream(keyStoreLocation), keypass.toCharArray());
319 320 321 322
            s2sTrustStore.store(new FileOutputStream(s2sTrustStoreLocation), s2sTrustpass.toCharArray());
            if (c2sTrustStore != s2sTrustStore) {
                c2sTrustStore.store(new FileOutputStream(c2sTrustStoreLocation), c2sTrustpass.toCharArray());
            }
323 324 325 326 327 328 329 330 331
        }
        catch (IOException e) {
            throw e;
        }
        catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

332 333 334 335 336
    /**
     * Create a ServerSocket for s2s connections
     *
     * @return the ServerSocket for an s2s connection
     */
337 338
    public static ServerSocket createServerSocket(int port, InetAddress ifAddress) throws
            IOException {
339
        if (s2sFactory == null) {
340 341 342
            throw new IOException();
        }
        else {
343
            return s2sFactory.createServerSocket(port, -1, ifAddress);
344 345
        }
    }
Alex Wenckus's avatar
Alex Wenckus committed
346

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
    /**
     * Create a ServerSocket for c2s connections
     *
     * @return the ServerSocket for an c2s connection
     */
    public static ServerSocket createc2sServerSocket(int port, InetAddress ifAddress) throws
            IOException {
        if (c2sFactory == null) {
            throw new IOException();
        }
        else {
            return c2sFactory.createServerSocket(port, -1, ifAddress);
        }
    }

    /**
     * Get the Key Store location
     *
     * @return the keystore location
     */
Alex Wenckus's avatar
Alex Wenckus committed
367 368 369 370
    public static String getKeystoreLocation() {
        return keyStoreLocation;
    }

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
    /**
     * Get the s2s Trust Store location
     *
     * @return the s2s Trust Store location
     */
    public static String gets2sTruststoreLocation() {
        return s2sTrustStoreLocation;
    }

    /**
     * Get the c2s Trust Store location
     *
     * @return the c2s Trust Store location
     */
    public static String getc2sTruststoreLocation() {
        return c2sTrustStoreLocation;
Alex Wenckus's avatar
Alex Wenckus committed
387 388 389 390 391 392
    }

    public static String getStoreType() {
        return storeType;
    }

393 394 395 396 397
    /**
     * Get the SSLContext for s2s connections
     *
     * @return the SSLContext for s2s connections
     */
398
    public static SSLContext getSSLContext() {
399
        return s2sContext;
400 401
    }

402 403 404 405 406 407 408 409 410 411 412 413 414 415
    /**
     * Get the SSLContext for c2s connections
     *
     * @return the SSLContext for c2s connections
     */
    public static SSLContext getc2sSSLContext() {
        return c2sContext;
    }

    /**
     * Get the SSLServerSocketFactory for s2s connections
     *
     * @return the SSLServerSocketFactory for s2s connections
     */
416
    public static SSLServerSocketFactory getServerSocketFactory() {
417 418 419 420 421 422 423 424 425
        return s2sFactory;
    }
    /**
     * Get the SSLServerSocketFactory for c2s connections
     *
     * @return the SSLServerSocketFactory for c2s connections
     */
    public static SSLServerSocketFactory getc2sServerSocketFactory() {
        return c2sFactory;
Alex Wenckus's avatar
Alex Wenckus committed
426
    }
427
}