07-25-2008 06:41 PM
While some protocols let you connect directly with SSL enabled (passing "ssl://" to Connector.open), others require that you first open a plain TCP socket connection, then send the "STARTTLS" command, then start talking SSL.
What I want to know, is how you switch from a plain StreamConnection to a SecureConnection in mid-flight.
I noticed that when I do open a secure connection, Connector.open actually instantiates TLS10Connection. This class does have a constructor which allows it to wrap an existing StreamConnection. However, my own experimentation has shown that I cannot even do what I want with directly instantiating TLS10Connection (I tried on the simulator). Any and all attempts end in some sort of exception, as that class only wants to be created to wrap a not-yet-opened StreamConnection.
Its not that uncommon to find protocols that want you to connect in-the-clear, do that initial capabilities check, then switch to SSL mode, so this is becoming a real hurdle. While those protocols sometimes are implemented with a straight-SSL port, that is often a less common implementation.
Solved! Go to Solution.
07-25-2008 07:12 PM
There is a recent post in the old forum, regarding an issue that seems similar to what you are asking. See:
http://www.blackberry.com/developers/forum/thread.
07-25-2008 07:27 PM
Yeah, that post basically says "Sorry, you can't do that." Was kinda hoping that with a newer, far more active forum, I might get a better response.
The only workable solution I've even heard of so far, is completely managing the SSL part inside my app. To do that, I'd use some standalone J2ME-compatable SSL library like Bouncy Castle.
07-26-2008 04:09 PM
Style of the new forum wont change the substance ;-)
We had to switch to BouncyCastle as well - which works fine but increases the size of the code.
One hopes that RIM will fix this ( as well as correct the documentation that seems to imply you can do the switch but in practice doesnt work)
10-30-2008 05:39 PM
Bumping this up.
At the recent Blackberry Developers Conference a number of speakers from RIM ( Mike K etc. ) indicated that they believed that this should work fine.
I am hoping that they would comment with a code fragment that shows how starttls can be made to work
12-11-2008 07:56 PM
05-11-2009 02:20 PM
Is there an update on this issue from RIM ?
08-01-2009 10:55 AM
I can't believe I didn't figure this out earlier, but assuming you can build code that instantiates TLS10Connection (requires the crypto signing key, not sure of any remaining legal issues exist there), you actually can do this. It just requires a little bit of trickery.
First, you open your connection as usual:
StreamConnection socket = (StreamConnection)Connector.open(
"socket://" + serverName + ":" + serverPort,
Connector.READ_WRITE, true);
DataInputStream input = socket.openDataInputStream();
DataOutputStream output = socket.openDataOutputStream();
Then you do whatever protocol I/O is necessary to handshake with the server, query its capabilities, etc. Finally, you send "STARTTLS\r\n", and now want to switch the mode of the socket. Here's how:
TLS10Connection tlsSocket = new TLS10Connection(
new StreamConnectionWrapper(socket, input, output),
serverName + ":" + serverPort,
true);
input = tlsSocket.openDataInputStream();
output = tlsSocket.openDataOutputStream();
The secret to this is StreamConnectionWrapper. You see, if you try creating a TLS10Connection with the original StreamConnection, it will try opening the input/output streams again. This causes I/O exceptions which break everything. So, here's the extremely simple code to the wrapper:
private class StreamConnectionWrapper implements StreamConnection {
private StreamConnection stream;
private DataInputStream dataInputStream;
private DataOutputStream dataOutputStream;
public StreamConnectionWrapper(
StreamConnection stream,
DataInputStream dataInputStream,
DataOutputStream dataOutputStream) {
this.stream = stream;
this.dataInputStream = dataInputStream;
this.dataOutputStream = dataOutputStream;
}
public DataInputStream openDataInputStream() throws IOException {
return dataInputStream;
}
public InputStream openInputStream() throws IOException {
return dataInputStream;
}
public void close() throws IOException {
stream.close();
}
public DataOutputStream openDataOutputStream() throws IOException {
return dataOutputStream;
}
public OutputStream openOutputStream() throws IOException {
return dataOutputStream;
}
}
And that's all there is to it! I seriously can't believe I didn't think of this workaround years ago.
08-01-2009 11:59 AM
We got it working couple of months ago using the same or similar work around technique - should have posted the results. Sorry.
The only annoyance we found is the native TLS libs dont let you over ride the certificate validation, while the external library we were using did. Most of the servers our users use dont have CA issued certificats and it introduces several extra steps during initial establishments as the process for storing the certs in the cert store etc is a bit confusing for an ordinary user.
I would be interested to know if you see bettery baterry consumption with the native lib compared to 3rd party libs i.e. if these are optimized in any way. It certainly saves on the memory as we dont have to pack the external lib.
08-02-2009 10:52 AM
Certificate-related popups have certainly been annoying my users quite a bit as well. For my own personal use cases, I get them through CAcert.org, and use the BlackBerry Desktop software to load the CAcert root certificate on my BB. For everyone else, that's probably a bit too much to ask.
While we can debate the whole source of this issue (and get into a whole rant over SSL itself and the CA system), that probably wouldn't be very productive here. But we do have a couple of separate issues to overcome before people stop complaining. Self-signed certs (easy to overcome if you load the CA cert with the desktop software), and invalid (expired or name mismatch) certs. Even some desktop clients whine about invalid certs, but at least some of them let you store a permanent exception.
As far as battery life, I don't know of any easy and reproducible way to measure that (other than time-consuming device testing, with too many other variables). I've got several use cases in my app where I'm curious to know (mainly about overhead of maintaining a connection versus periodically opening one, especially with TCP and/or SSL handshake overhead).