1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2003-2005 Jive Software.
7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License.
10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at
11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *     http://www.apache.org/licenses/LICENSE-2.0
13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software
15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS,
16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and
18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License.
19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smack;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport javax.net.ssl.X509TrustManager;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.FileInputStream;
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.InputStream;
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.IOException;
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.security.*;
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.security.cert.CertificateException;
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.security.cert.CertificateParsingException;
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.security.cert.X509Certificate;
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.*;
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.regex.Matcher;
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.regex.Pattern;
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Trust manager that checks all certificates presented by the server. This class
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * is used during TLS negotiation. It is possible to disable/enable some or all checkings
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * by configuring the {@link ConnectionConfiguration}. The truststore file that contains
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * knows and trusted CA root certificates can also be configure in {@link ConnectionConfiguration}.
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Gaston Dombiak
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenclass ServerTrustManager implements X509TrustManager {
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static Pattern cnPattern = Pattern.compile("(?i)(cn=)([^,]*)");
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private ConnectionConfiguration configuration;
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Holds the domain of the remote server we are trying to connect
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private String server;
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private KeyStore trustStore;
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static Map<KeyStoreOptions, KeyStore> stores = new HashMap<KeyStoreOptions, KeyStore>();
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public ServerTrustManager(String server, ConnectionConfiguration configuration) {
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.configuration = configuration;
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.server = server;
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        InputStream in = null;
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        synchronized (stores) {
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            KeyStoreOptions options = new KeyStoreOptions(configuration.getTruststoreType(),
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    configuration.getTruststorePath(), configuration.getTruststorePassword());
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (stores.containsKey(options)) {
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                trustStore = stores.get(options);
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } else {
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                try {
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    trustStore = KeyStore.getInstance(options.getType());
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    in = new FileInputStream(options.getPath());
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    trustStore.load(in, options.getPassword().toCharArray());
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                } catch (Exception e) {
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    trustStore = null;
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    e.printStackTrace();
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                } finally {
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (in != null) {
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        try {
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            in.close();
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        } catch (IOException ioe) {
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            // Ignore.
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                stores.put(options, trustStore);
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (trustStore == null)
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Disable root CA checking
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                configuration.setVerifyRootCAEnabled(false);
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public X509Certificate[] getAcceptedIssuers() {
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return new X509Certificate[0];
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void checkClientTrusted(X509Certificate[] arg0, String arg1)
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throws CertificateException {
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void checkServerTrusted(X509Certificate[] x509Certificates, String arg1)
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            throws CertificateException {
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        int nSize = x509Certificates.length;
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        List<String> peerIdentities = getPeerIdentity(x509Certificates[0]);
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (configuration.isVerifyChainEnabled()) {
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Working down the chain, for every certificate in the chain,
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // verify that the subject of the certificate is the issuer of the
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // next certificate in the chain.
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            Principal principalLast = null;
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (int i = nSize -1; i >= 0 ; i--) {
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                X509Certificate x509certificate = x509Certificates[i];
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                Principal principalIssuer = x509certificate.getIssuerDN();
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                Principal principalSubject = x509certificate.getSubjectDN();
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (principalLast != null) {
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    if (principalIssuer.equals(principalLast)) {
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        try {
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            PublicKey publickey =
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                    x509Certificates[i + 1].getPublicKey();
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            x509Certificates[i].verify(publickey);
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        catch (GeneralSecurityException generalsecurityexception) {
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            throw new CertificateException(
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                    "signature verification failed of " + peerIdentities);
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        }
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    else {
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        throw new CertificateException(
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                                "subject/issuer verification failed of " + peerIdentities);
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                principalLast = principalSubject;
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (configuration.isVerifyRootCAEnabled()) {
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Verify that the the last certificate in the chain was issued
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // by a third-party that the client trusts.
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            boolean trusted = false;
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            try {
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                trusted = trustStore.getCertificateAlias(x509Certificates[nSize - 1]) != null;
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (!trusted && nSize == 1 && configuration.isSelfSignedCertificateEnabled())
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                {
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    System.out.println("Accepting self-signed certificate of remote server: " +
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                            peerIdentities);
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    trusted = true;
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            catch (KeyStoreException e) {
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                e.printStackTrace();
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (!trusted) {
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new CertificateException("root certificate not trusted of " + peerIdentities);
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (configuration.isNotMatchingDomainCheckEnabled()) {
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Verify that the first certificate in the chain corresponds to
161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // the server we desire to authenticate.
162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Check if the certificate uses a wildcard indicating that subdomains are valid
163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (peerIdentities.size() == 1 && peerIdentities.get(0).startsWith("*.")) {
164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Remove the wildcard
165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                String peerIdentity = peerIdentities.get(0).replace("*.", "");
166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Check if the requested subdomain matches the certified domain
167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (!server.endsWith(peerIdentity)) {
168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    throw new CertificateException("target verification failed of " + peerIdentities);
169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            else if (!peerIdentities.contains(server)) {
172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                throw new CertificateException("target verification failed of " + peerIdentities);
173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (configuration.isExpiredCertificatesCheckEnabled()) {
177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // For every certificate in the chain, verify that the certificate
178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // is valid at the current time.
179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            Date date = new Date();
180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            for (int i = 0; i < nSize; i++) {
181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                try {
182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    x509Certificates[i].checkValidity(date);
183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                catch (GeneralSecurityException generalsecurityexception) {
185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    throw new CertificateException("invalid date of " + server);
186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the identity of the remote server as defined in the specified certificate. The
194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * identity is defined in the subjectDN of the certificate and it can also be defined in
195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * the subjectAltName extension of type "xmpp". When the extension is being used then the
196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * identity defined in the extension in going to be returned. Otherwise, the value stored in
197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * the subjectDN is returned.
198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param x509Certificate the certificate the holds the identity of the remote server.
200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the identity of the remote server as defined in the specified certificate.
201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public static List<String> getPeerIdentity(X509Certificate x509Certificate) {
203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // Look the identity in the subjectAltName extension if available
204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        List<String> names = getSubjectAlternativeNames(x509Certificate);
205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (names.isEmpty()) {
206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            String name = x509Certificate.getSubjectDN().getName();
207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            Matcher matcher = cnPattern.matcher(name);
208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (matcher.find()) {
209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                name = matcher.group(2);
210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Create an array with the unique identity
212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            names = new ArrayList<String>();
213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            names.add(name);
214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return names;
216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the JID representation of an XMPP entity contained as a SubjectAltName extension
220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * in the certificate. If none was found then return <tt>null</tt>.
221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param certificate the certificate presented by the remote entity.
223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the JID representation of an XMPP entity contained as a SubjectAltName extension
224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *         in the certificate. If none was found then return <tt>null</tt>.
225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static List<String> getSubjectAlternativeNames(X509Certificate certificate) {
227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        List<String> identities = new ArrayList<String>();
228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        try {
229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Check that the certificate includes the SubjectAltName extension
231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (altNames == null) {
232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return Collections.emptyList();
233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }
234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            // Use the type OtherName to search for the certified server name
235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            /*for (List item : altNames) {
236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                Integer type = (Integer) item.get(0);
237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (type == 0) {
238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    // Type OtherName found so return the associated value
239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    try {
240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Value is encoded using ASN.1 so decode it to get the server's identity
241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        ASN1InputStream decoder = new ASN1InputStream((byte[]) item.toArray()[1]);
242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        DEREncodable encoded = decoder.readObject();
243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        encoded = ((DERSequence) encoded).getObjectAt(1);
244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        encoded = ((DERTaggedObject) encoded).getObject();
245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        encoded = ((DERTaggedObject) encoded).getObject();
246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        String identity = ((DERUTF8String) encoded).getString();
247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Add the decoded server name to the list of identities
248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        identities.add(identity);
249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    catch (UnsupportedEncodingException e) {
251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Ignore
252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    catch (IOException e) {
254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        // Ignore
255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    catch (Exception e) {
257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                        e.printStackTrace();
258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    }
259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                }
260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                // Other types are not good for XMPP so ignore them
261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                System.out.println("SubjectAltName of invalid type found: " + certificate);
262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            }*/
263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        catch (CertificateParsingException e) {
265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            e.printStackTrace();
266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return identities;
268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private static class KeyStoreOptions {
271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private final String type;
272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private final String path;
273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        private final String password;
274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public KeyStoreOptions(String type, String path, String password) {
276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            super();
277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.type = type;
278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.path = path;
279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            this.password = password;
280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getType() {
283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return type;
284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getPath() {
287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return path;
288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public String getPassword() {
291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return password;
292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        @Override
295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public int hashCode() {
296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            final int prime = 31;
297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            int result = 1;
298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = prime * result + ((password == null) ? 0 : password.hashCode());
299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = prime * result + ((path == null) ? 0 : path.hashCode());
300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            result = prime * result + ((type == null) ? 0 : type.hashCode());
301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return result;
302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        @Override
305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        public boolean equals(Object obj) {
306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (this == obj)
307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return true;
308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (obj == null)
309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (getClass() != obj.getClass())
311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            KeyStoreOptions other = (KeyStoreOptions) obj;
313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (password == null) {
314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (other.password != null)
315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    return false;
316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } else if (!password.equals(other.password))
317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (path == null) {
319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (other.path != null)
320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    return false;
321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } else if (!path.equals(other.path))
322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            if (type == null) {
324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                if (other.type != null)
325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                    return false;
326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            } else if (!type.equals(other.type))
327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen                return false;
328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return true;
329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
332