Telit Cinterion IoT Developer Community
Java explicit FTPS implementation with BouncyCastle
Showcase, July 25, 2018 - 4:56pm, 6926 views
Introduction
The purpose of this showcase is to prepare the PoC for the Java explicit FTPS implementation.
Such approach could be an alternative for those who use Java on the modules and prefer a pure Java solutions over the built-in AT commands implementations.
BoucyCastle libraries were used to make it possible to implement an explicit version of FTPS (as defined in RFC 2228 and RFC 4217) where the connection is established on a standard FTP port, the request for encrypted connection is sent as plain text, then TLS handshake takes place and all the further traffic is encrypted.
To implement implicit FTPS no additional libraries are needed as the client connects on port 990 and the connection is secure from the very beginning. For that purpose SecureConnection could be used from the standard API. But that would be an easy way and not so funny.
Please see more about FTPS implicit and explicit modes and why explicit mode is more advisable here: https://en.wikipedia.org/wiki/FTPS
For FTP I have used ftp2me because it is very simple which fits the ***** of demo app. And was already used here https://iot-developer.thalesgroup.com/showcase/uart-ftp-pipe-example-java-midlet It is not well tested and there is no guarantee that it will work with all servers but for demo it's fine. I believe that it is possible to find in the network and adopt, if needed, some other FTP libraries.
The sources can be downloaded here: https://sourceforge.net/projects/ftp2me/files/ftp2me%20source%20releases/0.3%20beta/
BoucyCastle is quite complex and heavy for a small device (hundreds of class files) but it can handle TLS session and has J2ME version. It can be downloaded from here: https://www.bouncycastle.org/latest_releases.html
More details
For this demo project I downloaded lcrypto-j2me-160.zip package. Because of complexity I only imported source code from cldc_bccore_sources.zip and not all the src folder contents. Additionally deleted a few packages like all that was containing test in package name. No changes were made inside the remaining files.
As ftp2me does not originally support TLS connections I had to do some small changes to upgrade it. I have added a few commands in the control channel connection establishment routine to follow the sequence below:
socket()
bind()
socket()
connect() ----------------------------------------------> accept()
<---------------------------------------------- 220
AUTH TLS ---------------------------------------------->
<---------------------------------------------- 234
TLSneg() <----------------------------------------------> TLSneg()
PBSZ 0 ---------------------------------------------->
<---------------------------------------------- 200
PROT P ---------------------------------------------->
<---------------------------------------------- 200
USER fred ---------------------------------------------->
<---------------------------------------------- 331
PASS pass ---------------------------------------------->
<---------------------------------------------- 230
For control channel I have also created FtpsConnection class that was actually using BoucyCastle libraries to provide a socket connection transformable to secure connection on request.
For data channel SecureConnection form standard API could also be used but I have replaced it with my FtpsConnection class for test.
I didn’t implement anything more like switching back to plaintext connection with CCC command as the purpose of the whole thing was to provide a secure control and data channel.
The Main class just connects to the server, downloads one file and disconnects.
The first problem I have met was NoClassDefFoundError at runtime for a class from a package java.* that was added to BoucyCastle. There are a few such packages that contain some classes from standard Java API that are missing in J2ME. At the same time these classes were present in the MIDlet jar file. Renaming the packages from java.* to something else solved this problem.
Another issue was that the resulting MIDlet size was exceeding 3MB. It was possible to install it on ELS61 module but it was too much for EHS6 for example. Each attempt to install it on EHS6 was finished with ERROR. So here I have employed ProGuard (https://www.guardsquare.com/en/products/proguard) to reduce the MIDlet size. It can be done mainly by shrinking (removing unused classes, fields, methods and attributes) and obfuscation (renaming the remaining classes, fields, and methods using short meaningless names). This makes the code base smaller, more efficient, and additionally harder to reverse-engineer.
With the help of ProGuard the MIDlet size was reduced to over 600KB. And then it was possible to install it on EHS6 module. But then another problem has emerged. There was java.lang.Error thrown each time on the connection establishment. Some experiments with ProGuard settings resulted in the solution – adding -dontoptimize flag has solved the problem. For some reason code optimization was casing this error. The easiest and most safe solution was to tell ProGuard not to do it at all. Probably it would be possible to find some smarter solution that would not affect the entire code but it could be more time consuming and would not help much in MIDlet size reduction which was the main goal here.
The test application is connecting to one of the public ftps servers which was accepting FTPS connections at the moment of demo creation. In case of any problems please test the connection with some ftp client software.
Eclipse project with source code