Authentication: The sender of the message is who the receivers expect it to be (and/or vice versa).
These properties are usually achieved through a combination of various cryptographic techniques. While the details of these aren't terribly important for our purposes, it is useful to divide these techniques into two categories:
1. Symmetric key cryptosystems: Both the sender and receiver share the same keys.
2. Public key cryptosystems: The sender and receiver each have different keys (one called the public key and the other the private key).
Public key cryptosystems are extremely useful for Internet applications; unlike symmetric key systems they can be used to establish secure communications without requiring any prior relationship between the sender and receiver. However, they have a significant drawback - one that is particularly problematic for constrained devices such as cell phones - they require large amounts of computational power. This is a severe limitation on constrained platforms such as cell phones. To save on the cost and to increase the battery life of the device, CPU power is deliberately limited. This means that public key cryptography is typically only used to establish the initial connection (which can take anywhere from a few seconds to minutes on a low-powered device), and subsequent communication is secured using considerably faster symmetric key techniques.
An important concept provided by public key cryptography is a digital signature. It uses a private key to authenticate data in such a way that it can be verified by anyone with access to the public key. If only one user has access to the private key, this can be used to authenticate that user and also provide integrity protection of the signed data.
A final point to make about public key cryptosystems is that they require a mechanism to distribute public keys securely to users. This is done by using a certificate that contains the public key and is digitally signed by a third party called a Certification Authority whose public keys are known. Certificates can also be used to authenticate other certificates so they can be chained together back to a trusted root certificate.
Secure Sockets Layer
SSL is a protocol that is typically used in Internet applications to provide the three security "properties" for higher-level TCP/IP protocols such as HTTP. It consists of a handshake protocol that allows a client to negotiate security parameters and authenticate and exchange symmetric keys with a server, and a record protocol that can use these negotiated keys and parameters to encrypt data. A combination of public and symmetric key encryption is used to achieve the confidentiality, integrity, and authentication properties of the SSL connection. The particular combination of algorithms used is referred to as the ciphersuite. SSL supports a number of different algorithms including the RSA public key algorithm, MD5 and SHA-1 digest algorithms, and the RC4 and DES symmetric key algorithms.
Handshake Finished: This is the last message in the handshake, sent immediately after the ChangeCipherSpec message by both client and server, and is used to verify that the keys were exchanged correctly and to ensure the integrity of the message sent during the handshake. It is encrypted using the negotiated keys.
The most important part of the SSL protocol is the handshake. It's used to authenticate the peers and establish a set of symmetric keys for encrypting data using the record protocol. Figure 1 shows the flow of information in the handshake and a simplified explanation of the protocol follows:
While SSL provides a generic protocol for secure communication over TCP/IP, it is also commonly used to secure HTTP connections for Web browsers. The HTTPS protocol is simply the HTTP protocol performed over an SSL connection. Apart from some additional mechanisms to handle proxying of secure requests, the HTTPS protocol is identical to HTTP, only using SSL rather than raw TCP/IP as a transport and using the default port of 443, rather than 80.
A Secure Wireless E-Mail Application
That's all very interesting, but what does it mean for developers looking to deploy secure applications on J2ME MIDP platforms? To demonstrate how to use HTTPS we will look at a simple e-mail application that can connect to a Web server to retrieve e-mail headers and messages, allowing mobile users to browse their e-mail from their cell phone. HTTPS is a good choice for this application, as the infrastructure to support it is easily available, and we can quickly build the back end out of existing components without having to write much code (for this example it took approximately half a day to set up the back end starting from building the Web server source). Using this example, I'll demonstrate the basic concepts of using the javax.microedition.io.Connection interface to make an HTTPS connection to a server, show how you can authenticate the client using the standard HTTP Authentication mechanism, and then provide a sample MIDlet that can be used to seed the random number generator.
The Basic Application
Our basic application consists of a simple javax.microedition.lcdui GUI that allows the user to authenticate and select folders and messages to browse. Figure 2 shows the lcdui GUI for a wireless e-mail client example.
The back end is implemented as a simple CGI script that responds to commands and formats messages accordingly. Most of the processing is handled by the back end, with the client only being responsible for retrieving the data and presenting it to the user. To do this, a MIDlet invokes methods of the interface provided in Listing 1. (Listings 1-7 can be downoaded from below.)
The back end for each method is a simple GET operation over HTTPS. This means that each method may be implemented simply using the standard Connector.open mechanism in MIDP. Listing 2 shows how the getMsg method can be implemented.
That's pretty much all that's required to do a simple data retrieval over HTTPS. Seems easy doesn't it? A couple of things to note about the code:
Creating the HttpConnection instance in this code does not actually cause the connection. This only happens once the getResponseCode method is called. At this point the SSL handshake will be started, and when complete, the HTTP GET request will be sent to the server and the result retrieved. When we call openInputStream on the connection, we are sent an InputStream that contains the data returned from the HTTP request. In this case it's the text of the e-mail message we requested. The remaining code simply breaks the input up into an array of strings - one for each line.
Authenticating the Client
While this example seems simple, we're still missing a number of things that are needed to make a secure application. Most important is the fact that the standard Connector.open call does not provide any way of authenticating the client. Only the server is authenticated in this scenario.
Currently, while SSL supports client authentication using certificates, neither kSSL nor JCSI ME SSL support it. Furthermore, the new standard HttpsConnection interface has no provision for client authentication. This is somewhat understandable, as client authentication requires more messages to be exchanged in the handshake and more CPU power for an already expensive operation. Instead, we'll have to fall back on good old username/password authentication for this application. Fortunately, HTTP already has a basic authentication mechanism that is suitable for our purposes, but is a little tricky to implement.
When an HTTP server wishes to request authentication for access to a specific resource, it responds with a "401 Authorization Required" response. The response contains a "WWW-Authenticate" header field, which describes the authentication method requested. If the authentication method requested is of type "Basic," it also includes a string describing the realm for which the authentication should take place.
The client can then prompt the user for a username and password and resubmit the request using the Authorization request header, as follows:
Authorization: Basic <encoded username and password>
Where the encoded value consists of the username and password concatenated as follows:
and then encoded using the Base64 encoding method.
Implementing the HTTP Basic Authentication Scheme
The following example shows how we can use Basic authentication to authenticate the user in our application. Because we want to limit the amount of data to send, we're going to prompt for the username and password before we connect, and then perform a simple login command over HTTPS to ensure that the password works.
First we'll have to create a simple utility method to perform the Base64 encoding (see Listing 3).
Next we'll have to take the username and password and do the encoding. To do this, we'll implement the login method described in Listing 1 (see Listing 4).
Because we'll to want to use the same authenticator each time we make an HTTPS request, we'll create a simple utility method to perform the connection, and then call this from the login, getHeaders, and getEmailMsg methods (see Listing 5).
Now, the login method can call doCommand("?cmd=login") to attempt to log in. If successful, all the other methods of the EmailBackend implementation can also call this same doCommand method to get their data, and their requests will be authenticated.
Now we have an application that can not only do secure data transfer over HTTPS, but also ensures that the client is authenticated using a username and password. Surely our work here is done?
Seeding the Random Number Generator
A critical part of the SSL handshake is the generation and exchange of a set of symmetric keys for subsequent communications. Because these keys are generated randomly by the client, the MIDP SSL implementation requires a source of high-quality entropy (randomness or unguessability). If the generated keys are not sufficiently random, it is possible that an attacker will be able to guess enough of the material that they can recover the keys and break the security of the connection. The importance of this simple step cannot be stressed enough, and it is often overlooked in implementations of security protocols. This attack was practically demonstrated on an early version of the Netscape browser, which used simple sources of randomness such as the time and the process IDs of the application to seed the random number generator.
The MIDP specification assumes that the seeding of random number generators is taken care of in a meaningful way by the implementation. Unfortunately, Sun's current reference implementation does not do an adequate job and simply mixes in the current time in milliseconds. While it provides extra methods to supply seed to the random number generator, this functionality can't be accessed through the com.sun.kssl classes. This means that the reference implementation as it currently stands should not be used for production applications that require security.
If the MIDP SSL implementation does not provide a good source of entropy, it's possible that it may provide application-specific methods to seed the random number generator. To demonstrate how to generate random data when you don't have access to a good hardware source, we'll write a simple MIDlet that requires users to enter some random keys on their numeric keypad and use the timing information between presses. Even if a particular MIDP application does provide a good source of entropy, this MIDlet will still be useful for secure applications that are not using SSL or HTTPS (such as secure e-mail), as there is no interface in either MIDP 1.0 or MIDP 2.0 to gain access to the random entropy source in use.
One simple way to gather random data from a mobile device that has no guaranteed access to a good hardware source of entropy is to get the user to press keys randomly and measure the intervals between these key presses. This yields a small but sufficient amount of entropy (provided we gather enough key presses) that can be used to seed the random number generator. Listing 6 demonstrates how this can be achieved in MIDP using the keyPressed method of the javax.microedtion.lcdui.Canvas class.
The crux of this code is the keyPressed method, which is invoked each time a key is pressed. If the interval between the last key press and this one is nonzero, then the low order, 8 bits of the interval, is saved to a ByteArrayOutputStream. The code also updates a counter of the amount of gathered entropy. This number largely depends on the estimate given for the randomness of the key interval data (here I have arbitrarily chosen 4 bits, so that at least half of the data we save is considered unguessable). The number you use in your application depends largely on the specific distribution of the keypress intervals. For some devices that have low resolution timers or where the key polling interval is long, the entropy estimate may need to be less. While I have chosen to gather information from key presses here, on some MIDP devices you can also obtain information from the various pointer events. This can be done in a similar fashion to the code for keyPressed in Listing 6.
The constructor for this class takes the minimum amount of entropy required and a javax.microedition.lcdui.Command object. Once the minimum amount of entropy is gathered, the passed-in Command object is added to the list of Commands for the KeyPressEntropyGatherer object. The handler for this command can then invoke the getEntropy method to retrieve the gathered data (see the SeedRngMIDlet in Listing 7).
In this example, I have omitted an implementation of the paint method, which can be used to give visual feedback to users about what is happening when they enter key presses. For this example, a simple lcdui GUI displaying a progress bar and giving the amount of entropy gathered was used. Figure 3 shows the KeyPressEntropyGatherer as displayed in IBM's WebSphere Studio Device Developer.
Random Number Seeding MIDlet
Now we have a mechanism that allows us to gather entropy in a cross-platform way; I'll demonstrate how this can be integrated into a particular MIDP implementation. Listing 7 shows how to write a MIDlet that does this for Wedgetail's JCSI ME SSL. This toolkit stores the seed in a special RMS store "jcsiSSL_seed". We can use the KeyPressEntropyGatherer class described earlier to gather randomness from the user and concatenate this with any existing seed material.
Security is an oft-neglected part of developing applications, so it's important to make sure you have a good understanding of the issues before embarking on an adventure in the world of Java wireless. While the HTTPS protocol is not supported by default in MIDP 1.0, implementations do exist, and the MIDP 2.0 specification defines a standard interface for HTTPS that can be used to develop applications.
Despite this fact, care must be taken to ensure that your application has access to a good source of random data or else all your secure programming will account for nothing. One mechanism is to provide a source of random entropy using the SeedRngMIDlet in Listing 7, but your success will depend largely on whether the HTTPS implementation for your MIDP platform supports this. So get to it, and maybe you can show those teenage hackers a thing or two!
SSL vs TLS
Netscape originally developed the SSL protocol for use in their Web browser. They released two different versions in their products: SSLv2 and SSLv3. When the Internet Engineering Task Force (IETF) was looking to develop a new standard for security for Internet applications, it chose to base this protocol on SSL, but confusingly called the new protocol Transport Layer Security (TLS) and gave it the v1 version number. Despite this, the differences between SSLv3 and TLSv1 are fairly small, and I use SSL in this article to mean either SSL or TLS.
Dean Povey is a technical analyst with Wedgetail Communications. He has spent the past six years working with information security and has published several papers in the fields of distributed systems security, access control, and PKI. He coauthored the PKI and cryptographic toolkits Oscar and uPKI, and has contributed to both Australian and International standards in security.