javacommons/gcfprotocols/secureconnection/javasrc/com/nokia/mj/impl/ssl/SecureConnectionImpl.java
/*
* Copyright (c) 2003-2005 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.mj.impl.ssl;
import java.io.IOException;
import javax.microedition.pki.CertificateException;
import javax.microedition.io.*;
import com.nokia.mj.impl.gcf.utils.UrlParser;
import com.nokia.mj.impl.gcf.utils.StreamConnectionBase;
import java.io.*;
// import com.nokia.mj.impl.socket.*;
import com.nokia.mj.impl.gcf.utils.DateUtil;
import com.nokia.mj.impl.utils.Logger;
import com.nokia.mj.impl.rt.support.Finalizer;
import com.nokia.mj.impl.rt.support.ApplicationUtils;
import com.nokia.mj.impl.rt.ui.RuntimeUiFactory;
import com.nokia.mj.impl.rt.ui.RuntimeUi;
import com.nokia.mj.impl.rt.ui.ConfirmData;
import com.nokia.mj.impl.connectionmanager.ConnectionManager;
import com.nokia.mj.impl.connectionmanager.AccessPoint;
import com.nokia.mj.impl.utils.ResourceLoader;
/**
* Secure Connection Implementation class.
*/
public class SecureConnectionImpl extends StreamConnectionBase implements
SecureConnection
{
private UrlParser iUri; // the uri of the secure connection
private int iSocketDesc; // the tcp socket to be secured
private Finalizer iFinalizer;
private boolean iConnectionOpen = false;
private static final int X509_V_OK = 0;
private boolean iOutputStreamOpenedOnce = false;
private boolean iInputStreamOpenedOnce = false;
private boolean iDataOutputStreamOpenedOnce = false;
private boolean iDataInputStreamOpenedOnce = false;
private boolean iInput = false;
private int iChoice = -1;
private ConnectionManager iCmInstance = null;
private AccessPoint iApn = null;
private static final String SSL_RES_NAME = "javassl";
private static final String LOCALISED_STRING_ID = "qtn_ssl_prompt_";
private static final String UNTRUSTED_CERTIFICATE_WARNING = "untrusted_certificate";
/**
* Constructs the SecureConnectionImpl.
*
* @param aUri
* the uri to which secure connection is opened
* @param aMode
* the with which secure connection is opened
* @param aSock
* the tcp socket, which has to be made secure
* @throws IOException
* in case of any IO errors
*/
public void showUI()
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo, "display ui called ");
RuntimeUi rui = RuntimeUiFactory.getRuntimeUi();
String[] ans = { "Yes", "No" };
String localisedWarning = ResourceLoader.getInstance(SSL_RES_NAME,
LOCALISED_STRING_ID).format(UNTRUSTED_CERTIFICATE_WARNING,
(Object[]) null);
ConfirmData conf = new ConfirmData(localisedWarning, ans, 0);
iInput = rui.confirm("SecureConnection", conf);
iChoice = conf.getAnswer();
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"confirmdata returned value : " + iInput + "selected button :"
+ iChoice);
}
public SecureConnectionImpl(UrlParser aUri, int aMode, int aSock,
ConnectionManager cm, AccessPoint apnInfo) throws IOException
{
super(aUri.toString(), aMode, false);
int ret;
int[] retval = new int[2];
iCmInstance = cm;
iApn = apnInfo;
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::SecureConnectionImpl()");
iSocketDesc = aSock;
if (iApn != null)
{
ret = _doHandshake(iNativePeerHandle, iSocketDesc, iApn.getType(),
iApn.getNapId(), retval);
}
else
{
ret = _doHandshake(iNativePeerHandle, iSocketDesc, -1, -1, retval);
}
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"setting access point return value =" + retval[0]);
if (iCmInstance != null)
{
if (retval[0] < 0)
{
// reset connection manager
iCmInstance.reset();
}
}
Logger.LOG(Logger.ESOCKET, Logger.EInfo, "ssl connect return value ="
+ ret);
if (ret < 0)
{
throw new IOException(
"Unable to open a secure connection. Posix error code: " + ret);
}
if (retval[1] < 0)
{
// validation of certificate failed
iConnectionOpen = true;
SecurityInfo tmpSecurityInfo = getSecurityInfo();
throw new CertificateException(
"Invalid server certificate. Symbian OS error code: "
+ retval[1],
tmpSecurityInfo.getServerCertificate(),
CertificateException.VERIFICATION_FAILED);
}
if (ret != X509_V_OK)
{
iConnectionOpen = true;
if (ret == 18) // open c error code for self signed certificate
{
showUI();
if (iInput == true)
{
if (iChoice == 0) // "Yes" option selected
{
Logger
.LOG(Logger.ESOCKET, Logger.EInfo,
"SecureConnectionImpl()- untrusted certificate accepted");
// Continue
}
else
{
// "No" option selected
SecurityInfo tmpSecurityInfo = getSecurityInfo();
if (tmpSecurityInfo.getServerCertificate() == null)
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"tmpSecurityInfo.getServerCertificate() is null");
else
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"tmpSecurityInfo.getServerCertificate() is not null");
throw new CertificateException(
"Untrusted server certificate", tmpSecurityInfo
.getServerCertificate(),
CertificateException.VERIFICATION_FAILED); // untrusted
// certificate
}
}
else
{
SecurityInfo tmpSecurityInfo = getSecurityInfo();
throw new CertificateException(
"Untrusted server certificate", tmpSecurityInfo
.getServerCertificate(),
CertificateException.VERIFICATION_FAILED); // untrusted
// certificate
}
}
else
{
SecurityInfo tmpSecurityInfo = getSecurityInfo();
throw new CertificateException("Untrusted server certificate",
tmpSecurityInfo.getServerCertificate(),
CertificateException.VERIFICATION_FAILED); // untrusted
// certificate
}
/*
* if(ret > 14) { ret = CertificateException.VERIFICATION_FAILED; }
*/
}
else
{
iConnectionOpen = true;
}
iFinalizer = createFinalizer();
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"--SecureConnectionImpl(), socketdescrip = " + iSocketDesc);
}
/**
* Creatives the native side handle for this secure connection.
*
* @param aUri
* the uri to which secure connection is opened
* @param aMode
* the with which secure connection is opened
* @param aTimeOut
* the timeout value for this connection
* @return the native handle
*/
public int createNativePeer(String aUri, int aMode, boolean aTimeOut)
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::createNativePeer()");
iUri = new UrlParser(aUri);
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"SecureConnectionImpl::createNativePeer() aUri = " + aUri
+ "aMode = " + aMode + "iUri.host = " + iUri.host);
int ret = _createNativePeer(aUri, aMode, iUri.host, iUri.port);
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::createNativePeer()");
return ret;
}
/**
* Please refer to Jsr 118
*/
public String getAddress() throws IOException
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::getAddress()");
String addr[] = new String[1];
if (iConnectionOpen == false)
{
throw new IOException(
"getAddress failed: connection is already closed");
}
int retValue = _getAddress(iNativePeerHandle, addr);
if (retValue < 0)
{
throw new IOException("getAddress failed. POSIX error code: "
+ retValue);
}
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::getAddress()");
return addr[0];
}
/**
* Please refer to Jsr 118
*/
public String getLocalAddress() throws IOException
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::getLocalAddress()");
String addr[] = new String[1];
if (iConnectionOpen == false)
{
throw new IOException(
"getLocalAddress failed: connection is already closed");
}
int retValue = _getLocalAddress(iNativePeerHandle, addr);
if (retValue < 0)
{
throw new IOException("getLocalAddress failed. POSIX error code: "
+ retValue);
}
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::getLocalAddress()");
return addr[0];
}
/**
* Please refer to Jsr 118
*/
public int getLocalPort() throws IOException
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::getLocalPort()");
if (iConnectionOpen == false)
{
throw new IOException(
"getLocalPort failed: connection is already closed");
}
int localPort = _getLocalPort(iNativePeerHandle);
if (localPort < 0)
{
throw new IOException("getLocalPort failed. POSIX error code: "
+ localPort);
}
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::getLocalPort()");
return localPort;
}
/**
* Please refer to Jsr 118
*/
public int getPort() throws IOException
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::getPort()");
if (iConnectionOpen == false)
{
throw new IOException("getPort failed: connection is already closed");
}
int result = _getport(iNativePeerHandle);
if (result < 0)
{
throw new IOException("getPort failed. POSIX error code: " + result);
}
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::getPort()");
return result;
}
/**
* Please refer to Jsr 118
*/
public int getSocketOption(byte aOption) throws IllegalArgumentException,
IOException
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::getSocketOption()");
if (iConnectionOpen == false)
{
throw new IOException(
"getSocketOption failed: connection is already closed");
}
checkOption(aOption);
int retVal = _getSocketOption(iNativePeerHandle, aOption);
if (retVal < 0)
{
throw new IOException("getSocketOption failed. POSIX error code: "
+ retVal);
}
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::getSocketOption()");
return retVal;
}
/**
* Please refer to Jsr 118
*/
public void setSocketOption(byte aOption, int aValue)
throws IllegalArgumentException, IOException
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::setSocketOption()");
if (iConnectionOpen == false)
{
throw new IOException(
"setSocketOption failed: connection is already closed");
}
checkOption(aOption);
if (aValue < 0)
{
throw new IllegalArgumentException(
"Incorrect value for setSocketOption");
}
int retval = _setSocketOption(iNativePeerHandle, aOption, aValue);
if (retval < 0)
{
throw new IOException("setSocketOption failed. POSIX error code: "
+ retval);
}
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::setSocketOption()");
}
private void checkOption(byte option) throws IllegalArgumentException
{
if ((option != DELAY) && (option != KEEPALIVE) && (option != LINGER)
&& (option != RCVBUF) && (option != SNDBUF))
{
throw new IllegalArgumentException("Unsupported socket option");
}
}
/**
* Please refer to Jsr 118
*/
public SecurityInfo getSecurityInfo() throws IOException
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::getSecurityInfo()");
if (iConnectionOpen == false)
{
throw new IOException(
"getSecurityInfo failed: connection is already closed");
}
String[] iStringArray = new String[9];
long version = 0;
int res = _getSecurityInfo(iNativePeerHandle, iStringArray);
SecurityInfo securityInfo = new SecurityInfoImpl(iStringArray);
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::getSecurityInfo()");
return securityInfo;
}
/**
* Please refer to Jsr 118
*/
public OutputStream openOutputStream() throws IOException
{
if (iOutputStreamOpenedOnce == true)
{
throw new IOException(
"OutputStream cannot be opened multiple times");
}
else
{
iOutputStreamOpenedOnce = true;
return super.openOutputStream();
}
}
/**
* Please refer to Jsr 118
*/
public DataOutputStream openDataOutputStream() throws IOException
{
if (iDataOutputStreamOpenedOnce == true)
{
throw new IOException(
"DataOutputStream cannot be opened multiple times");
}
else
{
iDataOutputStreamOpenedOnce = true;
return super.openDataOutputStream();
}
}
/**
* Please refer to Jsr 118
*/
public InputStream openInputStream() throws IOException
{
if (iInputStreamOpenedOnce == true)
{
throw new IOException("InputStream cannot be opened multiple times");
}
else
{
iInputStreamOpenedOnce = true;
return super.openInputStream();
}
}
/**
* Please refer to Jsr 118
*/
public DataInputStream openDataInputStream() throws IOException
{
if (iDataInputStreamOpenedOnce == true)
{
throw new IOException(
"DataInputStream cannot be opened multiple times");
}
else
{
iDataInputStreamOpenedOnce = true;
return super.openDataInputStream();
}
}
/**
* Please refer to Jsr 118
*/
public void close() throws IOException
{
Logger
.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::close() open flag = "
+ iConnectionOpen);
if (iConnectionOpen == true)
{
iConnectionOpen = false;
super.close(); // closes the input and outputstreams.
// If streams is closed only then the native is closed
if (isStreamsClosed() == true)
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"+SecureConnectionImpl::close() calling _close "
+ iConnectionOpen);
int ret = _close(iNativePeerHandle);
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::close() = close returned "
+ ret);
if (ret != 0)
{
throw new IOException("Posix error code : " + ret);
}
}
}
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"-SecureConnectionImpl::close()");
}
Finalizer createFinalizer()
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"creating a socket finalizer object ");
return new Finalizer()
{
public void finalizeImpl()
{
doFinalize();
}
};
}
public void doFinalize()
{
Logger.LOG(Logger.ESOCKET, Logger.EInfo,
"securesocket doFinalize() called :");
if (iConnectionOpen == true)
{
iConnectionOpen = false;
if (iNativePeerHandle != 0)
{
int ret = _close(iNativePeerHandle);
}
}
if (iNativePeerHandle != 0)
{
_dispose(iNativePeerHandle);
iNativePeerHandle = 0;
}
}
// Native calls
private native int _createNativePeer(String aUri, int aMode, String aHost,
int aPort);
private native int _doHandshake(int iNativePeerHandle, int iSocketDesc,
int type, int apn, int[] retval);
//private native int _addCertificate(int iNativePeerHandle);
private native int _getSecurityInfo(int iNativePeerHandle,
String[] aStringArray);
private native int _getAddress(int iNativePeerHandle, String[] aAddr);
private native int _getLocalAddress(int iNativePeerHandle, String[] aAddr);
private native int _getLocalPort(int iNativePeerHandle);
private native int _getport(int iNativePeerHandle);
private native int _setSocketOption(int iNativePeerHandle, int aOption,
int aValue);
private native int _getSocketOption(int iNativePeerHandle, int aOption);
private native int _close(int iNativePeerHandle);
private native void _dispose(int iNativePeerHandle);
}