/*
* $Id: PinTanSSLSocketFactory.java,v 1.1 2011/05/04 22:37:51 willuhn Exp $
*
* This file is part of HBCI4Java Copyright (C) 2001-2008 Stefan Palme
*
* HBCI4Java is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* HBCI4Java 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.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.kapott.hbci.comm;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.Date;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import org.kapott.hbci.manager.HBCIUtils;
import org.kapott.hbci.passport.AbstractPinTanPassport;
/* This SSLSocketFactory will be used in certain circumstances as a drop-in
* replacement for Java's standard SSLSocketFactory:
* - when certificate checking should be disabled (because we have to install
* an own SSLContext with a modified TrustManager in this case)
* - when we want to log the HTTP traffic going through the SSL socket
* (because in this case we have to create "LoggingSockets" instead of
* standard Java sockets)
*
* If none of this applies, Java's standard factory will be used.
*
* This socket factory works as a Delegator by creating a java standard socket
* first and then delegating all relevant API calls to the standard socket
* while hooking in some special code to log traffic etc...
*
* This socket factory CAN NOT BE USED WITH OPERA<10 because of a bug in operas
* Java plugin, so when using this class in a Java Applet in Opera, the user
* has to ENABLE certificate checking and DISABLE ssl-logging */
public class PinTanSSLSocketFactory
extends SSLSocketFactory
{
private SSLSocketFactory realSocketFactory;
public PinTanSSLSocketFactory(AbstractPinTanPassport passport)
{
try {
if (!passport.getCheckCert()) {
HBCIUtils.log(
"creating socket factory with disabled cert checking",
HBCIUtils.LOG_WARN);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null,
new TrustManager[] {new PinTanSSLTrustManager()},
new SecureRandom());
this.realSocketFactory = sslContext.getSocketFactory();
} else {
HBCIUtils.log("using system socket factory", HBCIUtils.LOG_DEBUG);
this.realSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public boolean debug()
{
return HBCIUtils.getParam("log.ssl.enable","0").equals("1");
}
private OutputStream getLogger()
{
OutputStream result;
String filename=HBCIUtils.getParam("log.ssl.filename");
if (filename==null || filename.length()==0) {
HBCIUtils.log("no log.ssl.filename specified - logging to HBCI4Java logger", HBCIUtils.LOG_WARN);
result=new HBCI4JavaLogOutputStream();
} else {
try {
result = new FileOutputStream(filename, true);
result.write('\n');
result.write(HBCIUtils.datetime2StringISO(new Date()).getBytes(
"ISO-8859-1"));
result.write('\n');
result.flush();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return result;
}
public Socket createSocket()
throws IOException
{
HBCIUtils.log("createSocket()", HBCIUtils.LOG_DEBUG2);
Socket sock=this.realSocketFactory.createSocket();
if (debug()) {
sock=new LoggingSocket(sock, getLogger());
}
return sock;
}
public Socket createSocket(Socket sock, String host, int port, boolean autoClose)
throws IOException
{
HBCIUtils.log("createSocket(sock,host,port,autoClose)", HBCIUtils.LOG_DEBUG2);
Socket result=this.realSocketFactory.createSocket(sock, host, port, autoClose);
if (debug()) {
result=new LoggingSocket(result, getLogger());
}
return result;
}
public String[] getDefaultCipherSuites()
{
return this.realSocketFactory.getDefaultCipherSuites();
}
public String[] getSupportedCipherSuites()
{
return this.realSocketFactory.getSupportedCipherSuites();
}
public Socket createSocket(String host, int port)
throws IOException, UnknownHostException
{
HBCIUtils.log("createSocket(host,port)", HBCIUtils.LOG_DEBUG2);
Socket sock=this.realSocketFactory.createSocket(host, port);
if (debug()) {
sock=new LoggingSocket(sock, getLogger());
}
return sock;
}
public Socket createSocket(InetAddress addr, int port)
throws IOException
{
HBCIUtils.log("createSocket(addr,port)", HBCIUtils.LOG_DEBUG2);
Socket sock=this.realSocketFactory.createSocket(addr, port);
if (debug()) {
sock=new LoggingSocket(sock, getLogger());
}
return sock;
}
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
throws IOException, UnknownHostException
{
HBCIUtils.log("createSocket(host,port,localHost,localPort)", HBCIUtils.LOG_DEBUG2);
Socket sock=this.realSocketFactory.createSocket(host, port, localHost, localPort);
if (debug()) {
sock=new LoggingSocket(sock, getLogger());
}
return sock;
}
public Socket createSocket(InetAddress addr, int port, InetAddress localHost, int localPort)
throws IOException
{
HBCIUtils.log("createSocket(addr,port,localHost,localPort)", HBCIUtils.LOG_DEBUG2);
Socket sock=this.realSocketFactory.createSocket(addr, port, localHost, localPort);
if (debug()) {
sock=new LoggingSocket(sock, getLogger());
}
return sock;
}
}