001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.spring;
018
019import java.io.InputStream;
020import java.net.MalformedURLException;
021import java.security.KeyStore;
022import java.security.NoSuchAlgorithmException;
023import java.security.SecureRandom;
024import java.security.Security;
025import java.security.cert.*;
026import java.util.ArrayList;
027import java.util.Arrays;
028import java.util.Collection;
029
030import javax.annotation.PostConstruct;
031import javax.net.ssl.*;
032
033import org.apache.activemq.broker.SslContext;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036import org.springframework.core.io.Resource;
037
038/**
039 * Extends the SslContext so that it's easier to configure from spring.
040 *
041 * @org.apache.xbean.XBean element="sslContext"
042 *
043 *
044 */
045public class SpringSslContext extends SslContext {
046
047    private static final transient Logger LOG = LoggerFactory.getLogger(SpringSslContext.class);
048
049    private String keyStoreType="jks";
050    private String trustStoreType="jks";
051
052    private String secureRandomAlgorithm="SHA1PRNG";
053    private String keyStoreAlgorithm=KeyManagerFactory.getDefaultAlgorithm();
054    private String trustStoreAlgorithm=TrustManagerFactory.getDefaultAlgorithm();
055
056    private String keyStore;
057    private String trustStore;
058
059    private String keyStoreKeyPassword;
060    private String keyStorePassword;
061    private String trustStorePassword;
062
063    private String crlPath;
064
065    /**
066     * JSR-250 callback wrapper; converts checked exceptions to runtime exceptions
067     *
068     * delegates to afterPropertiesSet, done to prevent backwards incompatible signature change.
069     */
070    @PostConstruct
071    private void postConstruct() {
072        try {
073            afterPropertiesSet();
074        } catch (Exception ex) {
075            throw new RuntimeException(ex);
076        }
077    }
078
079    /**
080     *
081     * @throws Exception
082     * @org.apache.xbean.InitMethod
083     */
084    public void afterPropertiesSet() throws Exception {
085        keyManagers.addAll(createKeyManagers());
086        trustManagers.addAll(createTrustManagers());
087        if( secureRandom == null ) {
088            secureRandom = createSecureRandom();
089        }
090    }
091
092    private SecureRandom createSecureRandom() throws NoSuchAlgorithmException {
093        return SecureRandom.getInstance(secureRandomAlgorithm);
094    }
095
096    private Collection<TrustManager> createTrustManagers() throws Exception {
097        boolean ocsp = Boolean.valueOf(Security.getProperty("ocsp.enable"));
098
099        KeyStore ks = createTrustManagerKeyStore();
100        if( ks ==null ) {
101            return new ArrayList<TrustManager>(0);
102        }
103        TrustManagerFactory tmf  = TrustManagerFactory.getInstance(trustStoreAlgorithm);
104        boolean initialized = false;
105        if ((ocsp || crlPath != null) && trustStoreAlgorithm.equalsIgnoreCase("PKIX")) {
106            PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(ks, new X509CertSelector());
107            if (crlPath != null) {
108                pkixParams.setRevocationEnabled(true);
109                Collection<? extends CRL> crlList = loadCRL();
110                if (crlList != null) {
111                    pkixParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(crlList)));
112                }
113            }
114            tmf.init(new CertPathTrustManagerParameters(pkixParams));
115            initialized = true;
116        }
117
118        if (!initialized) {
119            tmf.init(ks);
120        }
121
122        return Arrays.asList(tmf.getTrustManagers());
123    }
124
125    private Collection<KeyManager> createKeyManagers() throws Exception {
126        KeyStore ks = createKeyManagerKeyStore();
127        if( ks ==null ) {
128            return new ArrayList<KeyManager>(0);
129        }
130
131        KeyManagerFactory tmf  = KeyManagerFactory.getInstance(keyStoreAlgorithm);
132        tmf.init(ks, keyStoreKeyPassword == null ? (keyStorePassword==null? null : keyStorePassword.toCharArray()) : keyStoreKeyPassword.toCharArray());
133        return Arrays.asList(tmf.getKeyManagers());
134    }
135
136    private KeyStore createTrustManagerKeyStore() throws Exception {
137        if( trustStore ==null ) {
138            return null;
139        }
140
141        KeyStore ks = KeyStore.getInstance(trustStoreType);
142        InputStream is=Utils.resourceFromString(trustStore).getInputStream();
143        try {
144            ks.load(is, trustStorePassword==null? null : trustStorePassword.toCharArray());
145        } finally {
146            is.close();
147        }
148        return ks;
149    }
150
151    private KeyStore createKeyManagerKeyStore() throws Exception {
152        if( keyStore ==null ) {
153            return null;
154        }
155
156        KeyStore ks = KeyStore.getInstance(keyStoreType);
157        InputStream is=Utils.resourceFromString(keyStore).getInputStream();
158        try {
159            ks.load(is, keyStorePassword==null? null : keyStorePassword.toCharArray());
160        } finally {
161            is.close();
162        }
163        return ks;
164    }
165
166    public String getTrustStoreType() {
167        return trustStoreType;
168    }
169
170    public String getKeyStoreType() {
171        return keyStoreType;
172    }
173
174    public String getKeyStore() {
175        return keyStore;
176    }
177
178    public void setKeyStore(String keyStore) throws MalformedURLException {
179        this.keyStore = keyStore;
180    }
181
182    public String getTrustStore() {
183        return trustStore;
184    }
185
186    public void setTrustStore(String trustStore) throws MalformedURLException {
187        this.trustStore = trustStore;
188    }
189
190    public String getKeyStoreAlgorithm() {
191        return keyStoreAlgorithm;
192    }
193
194    public void setKeyStoreAlgorithm(String keyAlgorithm) {
195        this.keyStoreAlgorithm = keyAlgorithm;
196    }
197
198    public String getTrustStoreAlgorithm() {
199        return trustStoreAlgorithm;
200    }
201
202    public void setTrustStoreAlgorithm(String trustAlgorithm) {
203        this.trustStoreAlgorithm = trustAlgorithm;
204    }
205
206    public String getKeyStoreKeyPassword() {
207        return keyStoreKeyPassword;
208    }
209
210    public void setKeyStoreKeyPassword(String keyPassword) {
211        this.keyStoreKeyPassword = keyPassword;
212    }
213
214    public String getKeyStorePassword() {
215        return keyStorePassword;
216    }
217
218    public void setKeyStorePassword(String keyPassword) {
219        this.keyStorePassword = keyPassword;
220    }
221
222    public String getTrustStorePassword() {
223        return trustStorePassword;
224    }
225
226    public void setTrustStorePassword(String trustPassword) {
227        this.trustStorePassword = trustPassword;
228    }
229
230    public void setKeyStoreType(String keyType) {
231        this.keyStoreType = keyType;
232    }
233
234    public void setTrustStoreType(String trustType) {
235        this.trustStoreType = trustType;
236    }
237
238    public String getSecureRandomAlgorithm() {
239        return secureRandomAlgorithm;
240    }
241
242    public void setSecureRandomAlgorithm(String secureRandomAlgorithm) {
243        this.secureRandomAlgorithm = secureRandomAlgorithm;
244    }
245
246    public String getCrlPath() {
247        return crlPath;
248    }
249
250    public void setCrlPath(String crlPath) {
251        this.crlPath = crlPath;
252    }
253
254    private Collection<? extends CRL> loadCRL() throws Exception {
255        if (crlPath == null) {
256            return null;
257        }
258        Resource resource = Utils.resourceFromString(crlPath);
259        InputStream is = resource.getInputStream();
260        try {
261            return CertificateFactory.getInstance("X.509").generateCRLs(is);
262        } finally {
263            is.close();
264        }
265    }
266
267}