/* * This file is part of the Haven & Hearth game client. * Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and * Björn Johannessen <johannessen.bjorn@gmail.com> * * Redistribution and/or modification of this file is subject to the * terms of the GNU Lesser General Public License, version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Other parts of this source tree adhere to other copying * rights. Please see the file `COPYING' in the root directory of the * source tree for details. * * A copy the GNU Lesser General Public License is distributed along * with the source tree of which this file is a part in the file * `doc/LPGL-3'. If it is missing for any reason, please see the Free * Software Foundation's website at <http://www.fsf.org/>, or write * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA */ package haven; import java.io.*; import java.net.*; import java.security.*; import java.security.cert.*; import java.security.cert.Certificate; import javax.net.ssl.*; import java.nio.channels.SocketChannel; import java.nio.channels.UnresolvedAddressException; public class SslHelper { private KeyStore creds, trusted; private SSLContext ctx = null; private SSLSocketFactory sfac = null; private int tserial = 0; private char[] pw; private HostnameVerifier ver = null; public SslHelper() { creds = null; try { trusted = KeyStore.getInstance(KeyStore.getDefaultType()); trusted.load(null, null); } catch(Exception e) { throw(new Error(e)); } } private synchronized SSLContext ctx() { if(ctx == null) { TrustManagerFactory tmf; KeyManagerFactory kmf; try { ctx = SSLContext.getInstance("TLS"); tmf = TrustManagerFactory.getInstance("PKIX"); kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); KeyManager[] kms = null; tmf.init(trusted); if(creds != null) { kmf.init(creds, pw); kms = kmf.getKeyManagers(); } ctx.init(kms, tmf.getTrustManagers(), new SecureRandom()); } catch(NoSuchAlgorithmException e) { throw(new Error(e)); } catch(KeyStoreException e) { throw(new RuntimeException(e)); } catch(UnrecoverableKeyException e) { /* The key should be recoverable at this stage, since * it was loaded successfully. */ throw(new RuntimeException(e)); } catch(KeyManagementException e) { throw(new RuntimeException(e)); } } return(ctx); } private synchronized SSLSocketFactory sfac() { if(sfac == null) sfac = ctx().getSocketFactory(); return(sfac); } private void clear() { ctx = null; sfac = null; } public synchronized void trust(Certificate cert) { clear(); try { trusted.setCertificateEntry("cert-" + tserial++, cert); } catch(KeyStoreException e) { /* The keystore should have been initialized and should * not have the generated alias, so this should not * happen. */ throw(new RuntimeException(e)); } } public static Certificate loadX509(InputStream in) throws IOException, CertificateException { CertificateFactory fac = CertificateFactory.getInstance("X.509"); return(fac.generateCertificate(in)); } public synchronized void loadCredsPkcs12(InputStream in, char[] pw) throws IOException, CertificateException { clear(); try { creds = KeyStore.getInstance("PKCS12"); creds.load(in, pw); this.pw = pw; } catch(KeyStoreException e) { throw(new Error(e)); } catch(NoSuchAlgorithmException e) { throw(new Error(e)); } } public HttpsURLConnection connect(URL url) throws IOException { if(!url.getProtocol().equals("https")) throw(new MalformedURLException("Can only be used to connect to HTTPS servers")); HttpsURLConnection conn = (HttpsURLConnection)url.openConnection(); conn.setSSLSocketFactory(sfac()); if(ver != null) conn.setHostnameVerifier(ver); return(conn); } public HttpsURLConnection connect(String url) throws IOException { return(connect(new URL(url))); } public void ignoreName() { ver = new HostnameVerifier() { public boolean verify(String hostname, SSLSession sess) { return(true); } }; } public SSLSocket connect(Socket sk, String host, int port, boolean autoclose) throws IOException { return((SSLSocket)sfac().createSocket(sk, host, port, autoclose)); } public SSLSocket connect(String host, int port) throws IOException { Socket sk = new HackSocket(); sk.connect(new InetSocketAddress(host, port)); return(connect(sk, host, port, true)); } public boolean hasCreds() { return(creds != null); } }