SSLServerCertStore.java revision 12745:f068a4ffddd2
1/* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.security.provider.certpath.ssl; 27 28import java.io.IOException; 29import java.net.URI; 30import java.util.ArrayList; 31import java.util.Arrays; 32import java.util.Collection; 33import java.util.Collections; 34import java.util.List; 35import java.security.GeneralSecurityException; 36import java.security.InvalidAlgorithmParameterException; 37import java.security.Provider; 38import java.security.cert.CertificateException; 39import java.security.cert.CertSelector; 40import java.security.cert.CertStore; 41import java.security.cert.CertStoreException; 42import java.security.cert.CertStoreParameters; 43import java.security.cert.CertStoreSpi; 44import java.security.cert.CRLSelector; 45import java.security.cert.X509Certificate; 46import java.security.cert.X509CRL; 47import java.net.Socket; 48import java.net.URLConnection; 49import javax.net.ssl.HostnameVerifier; 50import javax.net.ssl.HttpsURLConnection; 51import javax.net.ssl.SSLContext; 52import javax.net.ssl.SSLSession; 53import javax.net.ssl.SSLEngine; 54import javax.net.ssl.SSLSocketFactory; 55import javax.net.ssl.TrustManager; 56import javax.net.ssl.X509ExtendedTrustManager; 57 58/** 59 * A CertStore that retrieves an SSL server's certificate chain. 60 */ 61public final class SSLServerCertStore extends CertStoreSpi { 62 63 private final URI uri; 64 private static final GetChainTrustManager trustManager; 65 private static final SSLSocketFactory socketFactory; 66 private static final HostnameVerifier hostnameVerifier; 67 68 static { 69 trustManager = new GetChainTrustManager(); 70 hostnameVerifier = new HostnameVerifier() { 71 public boolean verify(String hostname, SSLSession session) { 72 return true; 73 } 74 }; 75 76 SSLSocketFactory tempFactory; 77 try { 78 SSLContext context = SSLContext.getInstance("SSL"); 79 context.init(null, new TrustManager[] { trustManager }, null); 80 tempFactory = context.getSocketFactory(); 81 } catch (GeneralSecurityException gse) { 82 tempFactory = null; 83 } 84 85 socketFactory = tempFactory; 86 } 87 88 SSLServerCertStore(URI uri) throws InvalidAlgorithmParameterException { 89 super(null); 90 this.uri = uri; 91 } 92 93 public Collection<X509Certificate> engineGetCertificates 94 (CertSelector selector) throws CertStoreException { 95 96 try { 97 URLConnection urlConn = uri.toURL().openConnection(); 98 if (urlConn instanceof HttpsURLConnection) { 99 if (socketFactory == null) { 100 throw new CertStoreException( 101 "No initialized SSLSocketFactory"); 102 } 103 104 HttpsURLConnection https = (HttpsURLConnection)urlConn; 105 https.setSSLSocketFactory(socketFactory); 106 https.setHostnameVerifier(hostnameVerifier); 107 synchronized (trustManager) { 108 try { 109 https.connect(); 110 return getMatchingCerts( 111 trustManager.serverChain, selector); 112 } catch (IOException ioe) { 113 // If the server certificate has already been 114 // retrieved, don't mind the connection state. 115 if (trustManager.exchangedServerCerts) { 116 return getMatchingCerts( 117 trustManager.serverChain, selector); 118 } 119 120 // otherwise, rethrow the exception 121 throw ioe; 122 } finally { 123 trustManager.cleanup(); 124 } 125 } 126 } 127 } catch (IOException ioe) { 128 throw new CertStoreException(ioe); 129 } 130 131 return Collections.<X509Certificate>emptySet(); 132 } 133 134 private static List<X509Certificate> getMatchingCerts 135 (List<X509Certificate> certs, CertSelector selector) 136 { 137 // if selector not specified, all certs match 138 if (selector == null) { 139 return certs; 140 } 141 List<X509Certificate> matchedCerts = new ArrayList<>(certs.size()); 142 for (X509Certificate cert : certs) { 143 if (selector.match(cert)) { 144 matchedCerts.add(cert); 145 } 146 } 147 return matchedCerts; 148 } 149 150 public Collection<X509CRL> engineGetCRLs(CRLSelector selector) 151 throws CertStoreException 152 { 153 throw new UnsupportedOperationException(); 154 } 155 156 public static CertStore getInstance(URI uri) 157 throws InvalidAlgorithmParameterException 158 { 159 return new CS(new SSLServerCertStore(uri), null, "SSLServer", null); 160 } 161 162 /* 163 * An X509ExtendedTrustManager that ignores the server certificate 164 * validation. 165 */ 166 private static class GetChainTrustManager 167 extends X509ExtendedTrustManager { 168 169 private List<X509Certificate> serverChain = 170 Collections.<X509Certificate>emptyList(); 171 private boolean exchangedServerCerts = false; 172 173 @Override 174 public X509Certificate[] getAcceptedIssuers() { 175 return new X509Certificate[0]; 176 } 177 178 @Override 179 public void checkClientTrusted(X509Certificate[] chain, 180 String authType) throws CertificateException { 181 182 throw new UnsupportedOperationException(); 183 } 184 185 @Override 186 public void checkClientTrusted(X509Certificate[] chain, String authType, 187 Socket socket) throws CertificateException { 188 189 throw new UnsupportedOperationException(); 190 } 191 192 @Override 193 public void checkClientTrusted(X509Certificate[] chain, String authType, 194 SSLEngine engine) throws CertificateException { 195 196 throw new UnsupportedOperationException(); 197 } 198 199 @Override 200 public void checkServerTrusted(X509Certificate[] chain, 201 String authType) throws CertificateException { 202 203 exchangedServerCerts = true; 204 this.serverChain = (chain == null) 205 ? Collections.<X509Certificate>emptyList() 206 : Arrays.<X509Certificate>asList(chain); 207 208 } 209 210 @Override 211 public void checkServerTrusted(X509Certificate[] chain, String authType, 212 Socket socket) throws CertificateException { 213 214 checkServerTrusted(chain, authType); 215 } 216 217 @Override 218 public void checkServerTrusted(X509Certificate[] chain, String authType, 219 SSLEngine engine) throws CertificateException { 220 221 checkServerTrusted(chain, authType); 222 } 223 224 void cleanup() { 225 exchangedServerCerts = false; 226 serverChain = Collections.<X509Certificate>emptyList(); 227 } 228 } 229 230 /** 231 * This class allows the SSLServerCertStore to be accessed as a CertStore. 232 */ 233 private static class CS extends CertStore { 234 protected CS(CertStoreSpi spi, Provider p, String type, 235 CertStoreParameters params) 236 { 237 super(spi, p, type, params); 238 } 239 } 240} 241