/openfire/src/java/org/jivesoftware/openfire/net/SSLConfig.java

https://github.com/joechen2010/IM · Java · 456 lines · 283 code · 56 blank · 117 comment · 32 complexity · 8d1a31baf186ba7326a569eb736318ff MD5 · raw file

  1. /**
  2. * $RCSfile$
  3. * $Revision: 1217 $
  4. * $Date: 2005-04-11 18:11:06 -0300 (Mon, 11 Apr 2005) $
  5. *
  6. * Copyright (C) 2005-2008 Jive Software. All rights reserved.
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. package org.jivesoftware.openfire.net;
  21. import java.io.File;
  22. import java.io.FileInputStream;
  23. import java.io.FileOutputStream;
  24. import java.io.IOException;
  25. import java.net.InetAddress;
  26. import java.net.ServerSocket;
  27. import java.security.KeyStore;
  28. import java.security.cert.X509Certificate;
  29. import java.util.List;
  30. import javax.net.ssl.KeyManagerFactory;
  31. import javax.net.ssl.SSLContext;
  32. import javax.net.ssl.SSLServerSocketFactory;
  33. import javax.net.ssl.TrustManagerFactory;
  34. import org.jivesoftware.util.CertificateEventListener;
  35. import org.jivesoftware.util.CertificateManager;
  36. import org.jivesoftware.util.JiveGlobals;
  37. import org.slf4j.Logger;
  38. import org.slf4j.LoggerFactory;
  39. /**
  40. * Configuration of Openfire's SSL settings.
  41. *
  42. * @author Iain Shigeoka
  43. */
  44. public class SSLConfig {
  45. private static final Logger Log = LoggerFactory.getLogger(SSLConfig.class);
  46. private static SSLServerSocketFactory s2sFactory;
  47. private static SSLServerSocketFactory c2sFactory;
  48. private static String storeType;
  49. private static SSLContext s2sContext;
  50. private static SSLContext c2sContext;
  51. private static KeyStore keyStore;
  52. private static String keyStoreLocation;
  53. private static String keypass;
  54. private static KeyStore s2sTrustStore;
  55. private static String s2sTrustStoreLocation;
  56. private static String s2sTrustpass;
  57. private static KeyStore c2sTrustStore;
  58. private static String c2sTrustStoreLocation;
  59. private static String c2sTrustpass;
  60. private SSLConfig() {
  61. }
  62. static {
  63. storeType = JiveGlobals.getProperty("xmpp.socket.ssl.storeType", "jks");
  64. // Get the keystore location. The default location is security/keystore
  65. keyStoreLocation = JiveGlobals.getProperty("xmpp.socket.ssl.keystore",
  66. "resources" + File.separator + "security" + File.separator + "keystore");
  67. keyStoreLocation = JiveGlobals.getHomeDirectory() + File.separator + keyStoreLocation;
  68. // Get the keystore password. The default password is "changeit".
  69. keypass = JiveGlobals.getProperty("xmpp.socket.ssl.keypass", "changeit");
  70. keypass = keypass.trim();
  71. // Get the truststore location for c2s connections
  72. c2sTrustStoreLocation = JiveGlobals.getProperty("xmpp.socket.ssl.client.truststore",
  73. "resources" + File.separator + "security" + File.separator + "client.truststore");
  74. c2sTrustStoreLocation = JiveGlobals.getHomeDirectory() + File.separator + c2sTrustStoreLocation;
  75. c2sTrustpass = JiveGlobals.getProperty("xmpp.socket.ssl.client.trustpass", "changeit");
  76. c2sTrustpass = c2sTrustpass.trim();
  77. // Get the truststore location for s2s connections
  78. s2sTrustStoreLocation = JiveGlobals.getProperty("xmpp.socket.ssl.truststore",
  79. "resources" + File.separator + "security" + File.separator + "truststore");
  80. s2sTrustStoreLocation = JiveGlobals.getHomeDirectory() + File.separator + s2sTrustStoreLocation;
  81. // Get the truststore passwprd; default is "changeit".
  82. s2sTrustpass = JiveGlobals.getProperty("xmpp.socket.ssl.trustpass", "changeit");
  83. s2sTrustpass = s2sTrustpass.trim();
  84. // Load s2s keystore
  85. try {
  86. keyStore = KeyStore.getInstance(storeType);
  87. keyStore.load(new FileInputStream(keyStoreLocation), keypass.toCharArray());
  88. }
  89. catch (Exception e) {
  90. Log.error("SSLConfig startup problem.\n" +
  91. " storeType: [" + storeType + "]\n" +
  92. " keyStoreLocation: [" + keyStoreLocation + "]\n" +
  93. " keypass: [" + keypass + "]\n", e);
  94. keyStore = null;
  95. s2sFactory = null;
  96. }
  97. // Load s2s trusstore
  98. try {
  99. s2sTrustStore = KeyStore.getInstance(storeType);
  100. s2sTrustStore.load(new FileInputStream(s2sTrustStoreLocation), s2sTrustpass.toCharArray());
  101. }
  102. catch (Exception e) {
  103. Log.error("SSLConfig startup problem.\n" +
  104. " storeType: [" + storeType + "]\n" +
  105. " s2sTrustStoreLocation: [" + s2sTrustStoreLocation + "]\n" +
  106. " s2sTrustpass: [" + s2sTrustpass + "]\n", e);
  107. s2sTrustStore = null;
  108. s2sFactory = null;
  109. }
  110. // Load c2s trusstore
  111. try {
  112. if (s2sTrustStoreLocation.equals(c2sTrustStoreLocation)) {
  113. c2sTrustStore = s2sTrustStore;
  114. c2sTrustpass = s2sTrustpass;
  115. }
  116. else {
  117. c2sTrustStore = KeyStore.getInstance(storeType);
  118. c2sTrustStore.load(new FileInputStream(c2sTrustStoreLocation), c2sTrustpass.toCharArray());
  119. }
  120. }
  121. catch (Exception e) {
  122. try {
  123. c2sTrustStore = KeyStore.getInstance(storeType);
  124. c2sTrustStore.load(null, c2sTrustpass.toCharArray());
  125. }
  126. catch (Exception ex) {
  127. Log.error("SSLConfig startup problem.\n" +
  128. " storeType: [" + storeType + "]\n" +
  129. " c2sTrustStoreLocation: [" + c2sTrustStoreLocation + "]\n" +
  130. " c2sTrustPass: [" + c2sTrustpass + "]", e);
  131. c2sTrustStore = null;
  132. c2sFactory = null;
  133. }
  134. }
  135. resetFactory();
  136. // Reset ssl factoty when certificates are modified
  137. CertificateManager.addListener(new CertificateEventListener() {
  138. // Reset ssl factory since keystores have changed
  139. public void certificateCreated(KeyStore keyStore, String alias, X509Certificate cert) {
  140. resetFactory();
  141. }
  142. public void certificateDeleted(KeyStore keyStore, String alias) {
  143. resetFactory();
  144. }
  145. public void certificateSigned(KeyStore keyStore, String alias, List<X509Certificate> certificates) {
  146. resetFactory();
  147. }
  148. });
  149. }
  150. private static void resetFactory() {
  151. try {
  152. String algorithm = JiveGlobals.getProperty("xmpp.socket.ssl.algorithm", "TLS");
  153. s2sContext = SSLContext.getInstance(algorithm);
  154. c2sContext = SSLContext.getInstance(algorithm);
  155. KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
  156. keyFactory.init(keyStore, SSLConfig.getKeyPassword().toCharArray());
  157. TrustManagerFactory s2sTrustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
  158. s2sTrustFactory.init(s2sTrustStore);
  159. s2sContext.init(keyFactory.getKeyManagers(),
  160. s2sTrustFactory.getTrustManagers(),
  161. new java.security.SecureRandom());
  162. s2sFactory = s2sContext.getServerSocketFactory();
  163. if (s2sTrustStore == c2sTrustStore) {
  164. c2sContext = s2sContext;
  165. c2sFactory = s2sFactory;
  166. }
  167. else {
  168. TrustManagerFactory c2sTrustFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
  169. c2sTrustFactory.init(c2sTrustStore);
  170. c2sContext.init(keyFactory.getKeyManagers(),
  171. c2sTrustFactory.getTrustManagers(),
  172. new java.security.SecureRandom());
  173. c2sFactory = c2sContext.getServerSocketFactory();
  174. }
  175. }
  176. catch (Exception e) {
  177. Log.error("SSLConfig factory setup problem.\n" +
  178. " storeType: [" + storeType + "]\n" +
  179. " keyStoreLocation: [" + keyStoreLocation + "]\n" +
  180. " keypass: [" + keypass + "]\n" +
  181. " s2sTrustStoreLocation: [" + s2sTrustStoreLocation+ "]\n" +
  182. " s2sTrustpass: [" + s2sTrustpass + "]" +
  183. " c2sTrustStoreLocation: [" + c2sTrustStoreLocation + "]\n" +
  184. " c2sTrustpass: [" + c2sTrustpass + "]", e);
  185. keyStore = null;
  186. s2sTrustStore = null;
  187. c2sTrustStore = null;
  188. s2sFactory = null;
  189. c2sFactory = null;
  190. }
  191. }
  192. /**
  193. * Get the Key Store password
  194. *
  195. * @return the key store password
  196. */
  197. public static String getKeyPassword() {
  198. return keypass;
  199. }
  200. /**
  201. * Return the Trust Store password for s2s connections.
  202. *
  203. * @return the s2s trust store password.
  204. */
  205. public static String gets2sTrustPassword() {
  206. return s2sTrustpass;
  207. }
  208. /**
  209. * Return the Trust Store password for c2s connections.
  210. *
  211. * @return the c2s trust store password.
  212. */
  213. public static String getc2sTrustPassword() {
  214. return c2sTrustpass;
  215. }
  216. public static String[] getDefaultCipherSuites() {
  217. String[] suites;
  218. if (s2sFactory == null) {
  219. suites = new String[]{};
  220. }
  221. else {
  222. suites = s2sFactory.getDefaultCipherSuites();
  223. }
  224. return suites;
  225. }
  226. public static String[] getSupportedCipherSuites() {
  227. String[] suites;
  228. if (s2sFactory == null) {
  229. suites = new String[]{};
  230. }
  231. else {
  232. suites = s2sFactory.getSupportedCipherSuites();
  233. }
  234. return suites;
  235. }
  236. /**
  237. * Get the Key Store
  238. *
  239. * @return the Key Store
  240. */
  241. public static KeyStore getKeyStore() throws IOException {
  242. if (keyStore == null) {
  243. throw new IOException();
  244. }
  245. return keyStore;
  246. }
  247. /**
  248. * Get the Trust Store for s2s connections
  249. *
  250. * @return the s2s Trust Store
  251. */
  252. public static KeyStore gets2sTrustStore() throws IOException {
  253. if (s2sTrustStore == null) {
  254. throw new IOException();
  255. }
  256. return s2sTrustStore;
  257. }
  258. /**
  259. * Get the Trust Store for c2s connections
  260. *
  261. * @return the c2s Trust Store
  262. */
  263. public static KeyStore getc2sTrustStore() throws IOException {
  264. if (c2sTrustStore == null) {
  265. throw new IOException();
  266. }
  267. return c2sTrustStore;
  268. }
  269. /**
  270. * Initializes (wipes and recreates) the keystore, and returns the new keystore.
  271. *
  272. * @return Newly initialized keystore.
  273. */
  274. public static KeyStore initializeKeyStore() {
  275. try {
  276. keyStore = KeyStore.getInstance(storeType);
  277. keyStore.load(null, keypass.toCharArray());
  278. }
  279. catch (Exception e) {
  280. Log.error("Unable to initialize keystore: ", e);
  281. }
  282. return keyStore;
  283. }
  284. /**
  285. * Save all key and trust stores.
  286. */
  287. public static void saveStores() throws IOException {
  288. try {
  289. File keyStoreDirectory = new File(keyStoreLocation).getParentFile();
  290. if (!keyStoreDirectory.exists())
  291. keyStoreDirectory.mkdirs();
  292. keyStore.store(new FileOutputStream(keyStoreLocation), keypass.toCharArray());
  293. if (s2sTrustStore != null) {
  294. File s2sTrustStoreDirectory = new File(s2sTrustStoreLocation).getParentFile();
  295. if (!s2sTrustStoreDirectory.exists())
  296. s2sTrustStoreDirectory.mkdirs();
  297. s2sTrustStore.store(new FileOutputStream(s2sTrustStoreLocation), s2sTrustpass.toCharArray());
  298. }
  299. if (c2sTrustStore != null && c2sTrustStore != s2sTrustStore) {
  300. File c2sTrustStoreDirectory = new File(c2sTrustStoreLocation).getParentFile();
  301. if (!c2sTrustStoreDirectory.exists())
  302. c2sTrustStoreDirectory.mkdirs();
  303. c2sTrustStore.store(new FileOutputStream(c2sTrustStoreLocation), c2sTrustpass.toCharArray());
  304. }
  305. }
  306. catch (IOException e) {
  307. throw e;
  308. }
  309. catch (Exception e) {
  310. throw new IOException(e.getMessage());
  311. }
  312. }
  313. /**
  314. * Create a ServerSocket for s2s connections
  315. *
  316. * @return the ServerSocket for an s2s connection
  317. */
  318. public static ServerSocket createServerSocket(int port, InetAddress ifAddress) throws
  319. IOException {
  320. if (s2sFactory == null) {
  321. throw new IOException();
  322. }
  323. else {
  324. return s2sFactory.createServerSocket(port, -1, ifAddress);
  325. }
  326. }
  327. /**
  328. * Create a ServerSocket for c2s connections
  329. *
  330. * @return the ServerSocket for an c2s connection
  331. */
  332. public static ServerSocket createc2sServerSocket(int port, InetAddress ifAddress) throws
  333. IOException {
  334. if (c2sFactory == null) {
  335. throw new IOException();
  336. }
  337. else {
  338. return c2sFactory.createServerSocket(port, -1, ifAddress);
  339. }
  340. }
  341. /**
  342. * Get the Key Store location
  343. *
  344. * @return the keystore location
  345. */
  346. public static String getKeystoreLocation() {
  347. return keyStoreLocation;
  348. }
  349. /**
  350. * Get the s2s Trust Store location
  351. *
  352. * @return the s2s Trust Store location
  353. */
  354. public static String gets2sTruststoreLocation() {
  355. return s2sTrustStoreLocation;
  356. }
  357. /**
  358. * Get the c2s Trust Store location
  359. *
  360. * @return the c2s Trust Store location
  361. */
  362. public static String getc2sTruststoreLocation() {
  363. return c2sTrustStoreLocation;
  364. }
  365. public static String getStoreType() {
  366. return storeType;
  367. }
  368. /**
  369. * Get the SSLContext for s2s connections
  370. *
  371. * @return the SSLContext for s2s connections
  372. */
  373. public static SSLContext getSSLContext() {
  374. return s2sContext;
  375. }
  376. /**
  377. * Get the SSLContext for c2s connections
  378. *
  379. * @return the SSLContext for c2s connections
  380. */
  381. public static SSLContext getc2sSSLContext() {
  382. return c2sContext;
  383. }
  384. /**
  385. * Get the SSLServerSocketFactory for s2s connections
  386. *
  387. * @return the SSLServerSocketFactory for s2s connections
  388. */
  389. public static SSLServerSocketFactory getServerSocketFactory() {
  390. return s2sFactory;
  391. }
  392. /**
  393. * Get the SSLServerSocketFactory for c2s connections
  394. *
  395. * @return the SSLServerSocketFactory for c2s connections
  396. */
  397. public static SSLServerSocketFactory getc2sServerSocketFactory() {
  398. return c2sFactory;
  399. }
  400. }