SSLConfig.java 15.3 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 9 10 11 12 13 14 15 16 17 18
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
19 20
 */

21
package org.jivesoftware.openfire.net;
22 23 24 25 26 27 28 29

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;
30 31
import java.security.cert.X509Certificate;
import java.util.List;
32

33 34 35 36 37 38 39 40 41 42 43
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManagerFactory;

import org.jivesoftware.util.CertificateEventListener;
import org.jivesoftware.util.CertificateManager;
import org.jivesoftware.util.JiveGlobals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

44
/**
45
 * Configuration of Openfire's SSL settings.
46 47 48 49 50
 *
 * @author Iain Shigeoka
 */
public class SSLConfig {

51 52
	private static final Logger Log = LoggerFactory.getLogger(SSLConfig.class);

53 54 55 56 57 58 59
    private static SSLServerSocketFactory s2sFactory;
    private static SSLServerSocketFactory c2sFactory;

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

60 61
    private static KeyStore keyStore;
    private static String keyStoreLocation;
62 63 64 65 66 67 68 69 70 71
    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;

72 73 74 75 76

    private SSLConfig() {
    }

    static {
Alex Wenckus's avatar
Alex Wenckus committed
77
        storeType = JiveGlobals.getProperty("xmpp.socket.ssl.storeType", "jks");
78 79 80 81 82 83 84 85 86 87

        // 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();

88 89 90 91 92 93 94 95 96 97
        // 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",
98
                "resources" + File.separator + "security" + File.separator + "truststore");
99
        s2sTrustStoreLocation = JiveGlobals.getHomeDirectory() + File.separator + s2sTrustStoreLocation;
100

guus's avatar
guus committed
101
        // Get the truststore password; default is "changeit".
102 103
        s2sTrustpass = JiveGlobals.getProperty("xmpp.socket.ssl.trustpass", "changeit");
        s2sTrustpass = s2sTrustpass.trim();
104

105
        // Load s2s keystore
106 107 108
        try {
            keyStore = KeyStore.getInstance(storeType);
            keyStore.load(new FileInputStream(keyStoreLocation), keypass.toCharArray());
109 110 111 112 113 114 115 116 117
        }
        catch (Exception e) {
            Log.error("SSLConfig startup problem.\n" +
                    "  storeType: [" + storeType + "]\n" +
                    "  keyStoreLocation: [" + keyStoreLocation + "]\n" +
                    "  keypass: [" + keypass + "]\n", e);
            keyStore = null;
            s2sFactory = null;
        }
guus's avatar
guus committed
118
        // Load s2s truststore
119
        try {
120 121
            s2sTrustStore = KeyStore.getInstance(storeType);
            s2sTrustStore.load(new FileInputStream(s2sTrustStoreLocation), s2sTrustpass.toCharArray());
122 123 124 125
        }
        catch (Exception e) {
            Log.error("SSLConfig startup problem.\n" +
                    "  storeType: [" + storeType + "]\n" +
126
                    "  s2sTrustStoreLocation: [" + s2sTrustStoreLocation + "]\n" +
127
                    "  s2sTrustpass: [" + s2sTrustpass + "]\n", e); 
128 129
            s2sTrustStore = null;
            s2sFactory = null;
130
        }
guus's avatar
guus committed
131
        // Load c2s truststore
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
        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();
157

guus's avatar
guus committed
158
        // Reset SSL factory when certificates are modified
159
        CertificateManager.addListener(new CertificateEventListener() {
guus's avatar
guus committed
160
            // Reset SSL factory since keystores have changed
161
            public void certificateCreated(KeyStore keyStore, String alias, X509Certificate cert) {
162
                resetFactory();
163
            }
164

165
            public void certificateDeleted(KeyStore keyStore, String alias) {
166
                resetFactory();
167
            }
168

169 170
            public void certificateSigned(KeyStore keyStore, String alias, List<X509Certificate> certificates) {
                resetFactory();
171 172
            }
        });
173 174
    }

175 176 177 178
    private static void resetFactory() {
        try {
            String algorithm = JiveGlobals.getProperty("xmpp.socket.ssl.algorithm", "TLS");

179 180
            s2sContext = SSLContext.getInstance(algorithm);
            c2sContext = SSLContext.getInstance(algorithm);
181 182 183 184

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

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
            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);
201

202
                c2sContext.init(keyFactory.getKeyManagers(),
203
                    c2sTrustFactory.getTrustManagers(),
204 205
                    new java.security.SecureRandom());

206 207 208
                c2sFactory = c2sContext.getServerSocketFactory();
            }

209 210 211 212 213 214
        }
        catch (Exception e) {
            Log.error("SSLConfig factory setup problem.\n" +
                    "  storeType: [" + storeType + "]\n" +
                    "  keyStoreLocation: [" + keyStoreLocation + "]\n" +
                    "  keypass: [" + keypass + "]\n" +
215 216 217 218
                    "  s2sTrustStoreLocation: [" + s2sTrustStoreLocation+ "]\n" +
                    "  s2sTrustpass: [" + s2sTrustpass + "]" +
                    "  c2sTrustStoreLocation: [" + c2sTrustStoreLocation + "]\n" +
                    "  c2sTrustpass: [" + c2sTrustpass + "]", e);
219
            keyStore = null;
220 221 222 223
            s2sTrustStore = null;
            c2sTrustStore = null;
            s2sFactory = null;
            c2sFactory = null;
224 225 226
        }
    }

227 228 229 230 231
    /**
     * Get the Key Store password
     *
     * @return the key store password
     */
232 233 234 235
    public static String getKeyPassword() {
        return keypass;
    }

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
    /**
     * 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;
253 254 255 256
    }

    public static String[] getDefaultCipherSuites() {
        String[] suites;
257
        if (s2sFactory == null) {
258 259 260
            suites = new String[]{};
        }
        else {
261
            suites = s2sFactory.getDefaultCipherSuites();
262 263 264 265
        }
        return suites;
    }

266
    public static String[] getSupportedCipherSuites() {
267
        String[] suites;
268
        if (s2sFactory == null) {
269 270 271
            suites = new String[]{};
        }
        else {
272
            suites = s2sFactory.getSupportedCipherSuites();
273 274 275 276
        }
        return suites;
    }

277 278 279 280 281
    /**
     * Get the Key Store
     *
     * @return the Key Store
     */
282 283 284 285 286 287 288
    public static KeyStore getKeyStore() throws IOException {
        if (keyStore == null) {
            throw new IOException();
        }
        return keyStore;
    }

289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
    /**
     * 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) {
308 309
            throw new IOException();
        }
310
        return c2sTrustStore;
311 312
    }

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
    /**
     * 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;
    }

329 330 331
    /**
     * Save all key and trust stores.
     */
332 333
    public static void saveStores() throws IOException {
        try {
334 335 336
            File keyStoreDirectory = new File(keyStoreLocation).getParentFile();
            if (!keyStoreDirectory.exists())
                keyStoreDirectory.mkdirs();
337
            keyStore.store(new FileOutputStream(keyStoreLocation), keypass.toCharArray());
338

339 340 341 342 343 344
            if (s2sTrustStore != null) {
                File s2sTrustStoreDirectory = new File(s2sTrustStoreLocation).getParentFile();
                if (!s2sTrustStoreDirectory.exists())
                    s2sTrustStoreDirectory.mkdirs();
                s2sTrustStore.store(new FileOutputStream(s2sTrustStoreLocation), s2sTrustpass.toCharArray());
            }
345

346
            if (c2sTrustStore != null && c2sTrustStore != s2sTrustStore) {
347 348 349
                File c2sTrustStoreDirectory = new File(c2sTrustStoreLocation).getParentFile();
                if (!c2sTrustStoreDirectory.exists())
                    c2sTrustStoreDirectory.mkdirs();
350 351
                c2sTrustStore.store(new FileOutputStream(c2sTrustStoreLocation), c2sTrustpass.toCharArray());
            }
352 353 354 355 356 357 358 359 360
        }
        catch (IOException e) {
            throw e;
        }
        catch (Exception e) {
            throw new IOException(e.getMessage());
        }
    }

361 362 363 364 365
    /**
     * Create a ServerSocket for s2s connections
     *
     * @return the ServerSocket for an s2s connection
     */
366 367
    public static ServerSocket createServerSocket(int port, InetAddress ifAddress) throws
            IOException {
368
        if (s2sFactory == null) {
369 370 371
            throw new IOException();
        }
        else {
372
            return s2sFactory.createServerSocket(port, -1, ifAddress);
373 374
        }
    }
Alex Wenckus's avatar
Alex Wenckus committed
375

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
    /**
     * 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
396 397 398 399
    public static String getKeystoreLocation() {
        return keyStoreLocation;
    }

400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
    /**
     * 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
416 417 418 419 420 421
    }

    public static String getStoreType() {
        return storeType;
    }

422 423 424 425 426
    /**
     * Get the SSLContext for s2s connections
     *
     * @return the SSLContext for s2s connections
     */
427
    public static SSLContext getSSLContext() {
428
        return s2sContext;
429 430
    }

431 432 433 434 435 436 437 438 439 440 441 442 443 444
    /**
     * 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
     */
445
    public static SSLServerSocketFactory getServerSocketFactory() {
446 447 448 449 450 451 452 453 454
        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
455
    }
456
}