Article
MIDP Terminal Emulation, Part 4: Securing Your Mobile Communications
 
By Michael Powers, September 2005  

Read Part 1: A Terminal Emulator for MIDP
Read Part 2: Advanced Terminal Emulation for MIDP
Read Part 3: Custom Fonts for MIDP
Download the project code

In the previous articles in this series, we've used MIDP's networking capabilities to build a terminal emulator application. MIDTerm implements an ANSI terminal and uses the Telnet protocol to communicate over standard TCP/IP sockets, enabling users of mobile devices to interact with software running on remote computers.

In this article, we'll use MIDP 2.0's secure connection classes to encrypt MIDTerm's communications. We'll first take a look at why encryption is necessary and spend a little time explaining how public-key encryption works, then I'll show you how to implement support for secure sockets on both the mobile device and the server you're connecting to.

Contents
 
Why Bother?
Public-Key Cryptography
Of Secure Sockets and Shells
Defeating Man-in-the-Middle Attacks
SSL or SSH?
Supporting SSL in MIDTerm
Supporting SSL on the Server
Summary
For More Information
About the Author
 

Why Bother?

The venerable Telnet protocol was the backbone of the early Internet, but it has one serious drawback: All information is sent across the network "in the clear"; data carried in TCP/IP packets is not encoded, compressed, encrypted, or otherwise transformed. Anyone that's plugged into your network can observe those packets, and with the right software they can read everything you typed, including your user ID and your password. Freely available packet-sniffing tools like tcpdump and Ethereal make snooping on TCP/IP communications easy. See if you can find the password embedded in this packet sniffed from my network:

<nop,nop,timestamp 1731372647 1731372647> (DF)
0x0000	 4500 003c 2abf 4000 4006 11fb 7f00 0001	E..<*.@.@.......
0x0010	 7f00 0001 c577 0017 7506 8da9 b5a0 d39a	.....w..u.......
0x0020	 8018 ffff 5ab7 0000 0101 080a 6732 a667	....Z.......g2.g
0x0030	 6732 a667 6f74 6361 6b65 730a          	g2.gotcakes.

Not difficult, was it? If you're a mobile user, risks are even greater. Even though GSM and CDMA networks encrypt your data, wireless carriers typically route your packets through one or more gateways, each of which is a potential siphoning point for an interloper.

The modern Internet has so many unwary users that opportunities for mischief abound. Even if our data isn't super-sensitive, we don't want to be exploited. Let's take a look at how to secure the data we send.

Public-Key Cryptography

What we want to do is scramble sensitive message content in a way that lets the recipient, and only the recipient, figure out how to unscramble it. That's no easy trick. Fortunately, the best minds in mathematics and computer science have worked out cryptography systems that solve this problem. You can learn the voluminous details from many places on the web; I'll only briefly describe the techniques here.

Most people's only venture into cryptography is to password-encrypt a document. An encryption program uses a password you supply in the algorithm that scrambles your document, and that document can be decrypted only by someone who knows the password. It's equally true, though, to say that it can be decrypted by anyone who knows the password. This approach is great for securing your personal documents, when only you know the password, not so great when you want to send an encrypted document to someone else: You have to convey the password somehow so that the recipient can decrypt the document; how do you communicate the password itself safely?

If you send the password along with the document, you defeat the purpose of encrypting the document in the first place. If the recipient is someone you know, whispering your password over the phone may be sufficient. The weakness of password encryption shows up when you want to communicate securely with a third party that you don't know personally, like a gigantic online retailer. How do you share a secret password with someone you don't know?

The solution is public-key encryption. Modern cryptography programs split a password into two encryption keys. You give out the public key freely, but only you know the private key. The paired keys have a very neat feature: Messages encrypted using the public key can be decrypted only by someone who has the private key. If you know my public key you can send me an encrypted message that only I can decrypt, and if I know your public key I can send a reply that only you can decrypt.

Because encrypting with public and private keys is a whole lot more computationally intensive than simple encryption with a shared secret password, popular communications protocols use slow public-key encryption only to negotiate a randomly generated password, which both sides then use to encrypt subsequent communications more efficiently.

Of Secure Sockets and Shells

Two widely used communications protocols incorporate public-key cryptography. The more popular of the two, Transport Layer Security (TLS), defined in 1999 by The Internet Society as RFC 2246, is explained in detail from a MIDP perspective in a separate article, "MIDP Application Security 2: Understanding SSL and TLS". TLS is the Internet Engineering Task Force (IETF) standard for the widely deployed Secure Sockets Layer (SSL) protocol, which, as its designers intended, is used in every secure web transaction on the planet.

The familiar HTTPS protocol is simply the standard Hypertext Transfer Protocol (HTTP) running through an SSL-secured connection. SSL works by exchanging public keys, using them to generate and agree on a shared secret password, then getting out of the way. The protocol is transparent: Once it establishes the connection and the encryption method, other protocols like HTTP can run unmodified over it. For this reason, SSL is the standard way to secure email protocols like POP3 (which, when secured, is called POP3S) and IMAP (when secured, IMAPS). Likewise and important for our purposes, the secure Telnet protocol, Telnet/SSL, is the standard Telnet protocol running through an SSL connection.

By contrast, Secure Shell (SSH) is a protocol unto itself. SSH v2.0 consists of three sub-protocols: one for the transport layer itself, another for exchanging public keys to generate a shared secret key, and the third for securing other types of socket connections through a single SSH connection. As the name implies, SSH is a complete protocol for remote shell interaction and is clearly meant as a replacement for Telnet. It goes even further, supporting secure file copying and remote hosting of graphical applications. Using SSH's support for port forwarding, packets meant for one computer can be sent to another, allowing just about any Internet protocol to be tunneled through an SSH connection, although with somewhat less transparency than SSL.

You can see a key difference between TLS/SSL and SSH in how they handle the only major weakness of public-key cryptography: the man-in-the-middle attack.

Defeating Man-in-the-Middle Attacks

To open a connection with another computer, you normally use an Internet name, like www.mpowers.net, that gets translated into an Internet Protocol (IP) address to which your data packets are sent, such as 68.167.166.223. It turns out there are ways to hijack an Internet name so that it temporarily points to a different IP address, as well as ways to hijack an address directly.

Suppose I want to insert myself between you and a server I know you want to connect to, and read all the messages back and forth. I assume the identity of the server's name or address. When you ask for the server's public key, your request comes to me. I ask the server for its public key, and keep it, but give you my public key instead. When the server asks me for your public key, I ask you for it and keep it, but give the server my public key. Because you and the server then encrypt messages using my public key, I can decrypt every one of them. And because I have the public keys from you and the server, I can re-encrypt all the messages so that you and the server think that you're talking directly to each other. I know the content of every message between you and the server, and neither of you will ever know that I was there.

So how can you be sure that the computer you're connecting to is actually the computer you want to connect to? This uncertainty is called the problem of host authentication. SSL and SSH take different tacks in solving this problem.

SSL relies on organizations called certificate authorities (CAs) to vouch for claimed identities. Anyone with a public key can ask that a CA certify that key with the CA's own public key. If you know the CA's public key, you can find out whether someone else's public key has been certified by that CA. If you routinely exchange sensitive data only with servers whose public keys are accompanied by certificates from CAs that you trust, you're safe from my man-in-the-middle attack. If I give you my public key, you know that I'm not the server. If I just pass along the server's public key, I'm stymied: I don't have the server's private key so I can't decrypt the messages you encrypt.

Any person or organization can call itself a certificate authority, but in practice only a handful of CAs are trusted throughout the world; Verisign, Thawte, and Comodo are a few of the better-known ones. Web browsers come with the public keys of these trusted CAs pre-installed. If a secure server's certificate doesn't match the one installed, the browser displays a warning message with details about the server and the signer.

Nothing stops you from signing your own public key, but you may want the more authoritative certification that one of the big CAs can provide. If so, it will cost you at least a couple of hundred dollars.

SSH avoids the issue of third-party certification altogether, by requiring clients to record the public key of each server to which they connect. If the key is different on your next visit to that server, you'll see details about the server and a warning that you may be experiencing a man-in-the-middle attack. Of course a simple explanation is more likely – perhaps the owner of the server at that address replaced it with a newer machine with a different key – but at least you remain in control of your fate.

SSL or SSH?

Which public-key encryption protocol is the best choice for MIDTerm?

One factor to consider is the effort each option would require. MIDTerm already has a working implementation of the Telnet protocol; simply wrapping it in an SSL connection would give us a working implementation of the Telnet/SSL protocol. SSH is a completely different protocol. Even though we'd use the same ANSI terminal commands, getting SSH working would require substantially more new code.

What's more, an SSH implementation would require access to a number of cryptographic algorithms that don't exist in the MIDP specification, or indeed on most mobile devices. J2ME versions of these algorithms are freely available, in the BouncyCastle package for instance, but the footprint of these libraries is substantial and the impact on runtime performance perceptible.

By contrast, SSL capabilities are already built into many MIDP 2.0 devices and some MIDP 1.0 devices as well, because MIDP 2.0 requires the HTTPS protocol, which is usually built on SSL. Whether you can get to the raw SSL sockets is a different story. If the MIDP runtime allows you to create socket connections, there's a very good chance you can create secure socket connections as well. Using SSL in this case will have no impact on the size of our application and negligible impact on performance, because the cryptographic functions are likely to be performed in native code or perhaps even in hardware. That SSL is a standard part of the platform is a boon to MIDP developers, enabling us to write all manner of secure clients for common Internet services.

We must also consider the server side, though. Far more servers support SSH than support secure Telnet. Moreover, it's very easy to set up a computer for access over SSH because it doesn't rely on certificate authorities. Configuring a server for secure Telnet access is more complicated, mainly because it needs a signed certificate for its public key.

As you'll soon see, however, there's not too much complexity in implementing server-side SSL support, and it's more than offset by the reduction in the mobile client, where resources are limited. We'll start with the MIDlet.

Supporting SSL in MIDTerm

All the changes to implement SSL support in the MIDlet happen only in the MIDTerm class itself. TelnetConnection and the rest of the supporting classes are blissfully unaffected. Let's walk through the changes together.

First we give users an option to encrypt their communications by adding to the login form a checkbox and an ItemListener, so that the application can update the port field if the user switches from standard Telnet (port 23) to secure Telnet (port 992). The logic is very simple.

The New Login Form
public void itemStateChanged( Item item )
{
    if ( item == connectOptions )
    {
        String port = portField.getString().trim();
        if ( connectOptions.isSelected( 0 ) )
        {
            if ( "23".equals( port ) ||
                 port.length() == 0 )
            {
                portField.setString( "992" );
            }
        }
        else
        {
            if ( "992".equals( port ) ||
                 port.length() == 0 )
            {
                portField.setString( "23" );
            }
        }
    }
}

If users don't change the port field's default value, it's automagically updated when they check the encryption box. They don't need to remember particular port numbers but if they want to, they can easily override the default value. Because Telnet is a fairly transparent protocol (all bytes not equal to 255 just pass through), MIDTerm enables them to connect with servers that use other SSL-based protocols, testing an email server with POP3S (port 995) or IMAPS (port 993), or scraping secure web sites directly with HTTPS (port 443).

The actual call to obtain a secure connection is even easier. If the encryption box is checked, we change the protocol from socket:// to ssl://, as shown here:

...
String connectString;
if ( useSSL )
{
    connectString = "ssl://" + host + ':' + port;
}
else
{
    connectString = "socket://" + host + ':' + port;
}
...

If the device doesn't support the ssl:// protocol, an exception will be thrown and an error message will appear on the screen.

We've seen that host authentication is always a concern, so when the connection object is a SecureConnection, we obtain the Certificate for the server, extract information about the signer, and write it to the screen. This procedure lets users decide for themselves whether the signer is someone they recognize and trust. If not, they can still choose to proceed with caution.

CA-Signed Certificate
Self-Signed Certificate
...
// obtain actual connection
StreamConnection rawConnection = (StreamConnection) 
    Connector.open( connectString,
                    Connector.READ_WRITE,
                    true );

// create TelnetConnection
connection =
    new TelnetConnection( rawConnection,
                          canvas.getColumns(),
                          canvas.getRows(),
                          canvas.getTerminalType() );

input = connection.openInputStream();
output = connection.openOutputStream();
canvas.setOutputStream( output );

if ( useSSL )
{
    // get the certificate if any
    Certificate cert = 
        ((SecureConnection)rawConnection)
        .getSecurityInfo().getServerCertificate();
    if ( cert != null )
    {
        // parse and write the certificate info
        // to the screen
        canvas.receive( "Certificate issued by:\n" );
        String issuer = cert.getIssuer();
        int sep = issuer.indexOf( ';' );
        while ( sep != -1 )
        {
            canvas.receive( 
                toASCII( issuer.substring( 0, sep ) +
                         '\n' ) );
            issuer = issuer.substring( sep+1 );
            sep = issuer.indexOf( ';' );
        }
        canvas.receive( toASCII( issuer + '\n' ) );
    }
}
...

The signer information is contained in a single semicolon-delimited string. Here we parse the information and write each field to the screen.

Finally, we need to add explicit handling for a CertificateException that may be thrown when we connect. We expect users of a terminal emulator to be of a technical sort, so printing a message on the console should suffice.

An Untrusted Certificate
...
catch ( CertificateException ce )
{
    System.err.println( "Security Error: " +
                        ce.getMessage() );
    canvas.receive( toASCII( "Security Error: " +
                    ce.getMessage() ) );
}
...

This exception may be thrown for a variety of reasons, each of which the exception's message will describe. You're most likely to see this exception when the runtime decides it doesn't trust the server's signed certificate. We'd like to make our own determination whether the certificate is issued by a recognized certificate authority, and give our users an option to decide for themselves whether they're willing to proceed at the risk of a man-in-the-middle attack, but here we're out of luck: The MIDlet simply can't connect because the exception is thrown by the runtime environment. Any given implementation of the MIDP runtime could give the user a warning prompt before throwing the exception, but I haven't seen any that do so.

Most MIDP development environments and emulators give you the ability to add a signer's key to the built-in list of trusted certificate authorities. In the real world, however, each device will have a hard-coded set of trusted signers. If you want users to be able to connect to your own server, you're going to have pay your dues and get your certificate signed by a CA that's already widely trusted. It's a small price to pay if your users' data is worth securing.

Supporting SSL on the Server

Setting up a server to allow SSL connections is a straightforward process. Recall that SSL is a transparent protocol, so just about any Internet protocol can be "tunneled" through an SSL connection. The strategy, then, is to start a server process that listens to some port, handles the negotiating, encrypting, and decrypting, and forwards the data to a server process running on some other port.

An ideal tool for this task is stunnel, freely available, open source software that performs SSL-encrypted port forwarding. It runs on Unix (including Mac OS X) and Windows and a slew of other platforms; download and install the version that's right for you.

The installation process actually creates a public-private key pair with a self-signed certificate that will be used by default. If you have your own signed certificate, you'll want to remember to use that instead. When you're working with certificates on the server side, you'll find that most programs work with .pem files. There's a good discussion of these files on the stunnel.org site.)

Let's see how stunnel works. Assume your computer has a Telnet service running on port 23. You need to run an stunnel process that maps port 992, the Telnet/SSL port, to port 23.

First you need an stunnel configuration file. I called mine stunnel.conf and it looks like this:

cert = /var/yourfiles/yourcertificate.pem
[telnets]
connect=23
accept=992

Then, on the server, run stunnel with this command:

sudo /usr/local/sbin/stunnel stunnel.conf

On Unix you need to be a superuser to listen on a "privileged port," one whose number is 1023 or less. If this restriction is a problem for you, just pick a higher-numbered port.

The stunnel program can run as an NT service on Windows and as an inetd service on Unix. You'll want to do so, to make your secure port available on the server at all times, whether you're logged into the server or not.

With this infrastructure in place, you'll be protected when you use your mobile device to connect to your server. As a demonstration, here is a data packet containing the same password you saw all too easily earlier, but this time encrypted with SSL. You can see the difference:

<nop,nop,timestamp 1731850845 1731850845> (DF)
0x0000	 4500 006b c029 4000 4006 7c61 7f00 0001	E..k.)@.@.|a....
0x0010	 7f00 0001 03e0 e9ba 3fa5 0783 ee68 0702	........?....h..
0x0020	 8018 ffff 2574 0000 0101 080a 6739 f25d	....%t......g9.]
0x0030	 6739 f25d 1703 0000 32a4 2de0 5aeb d5b2	g9.]....2.-.Z...
0x0040	 cae4 359f 93c2 a8c4 1158 8801 d790 95fe	..5......X......
0x0050	 a92e f44b aa69 711d d8b3 0ffa 17c6 23f6	...K.iq.......#.
0x0060	 3b92 8124 57b7 afe9 becd 29            	;..$W.....)


Summary

We've seen the need for securing the communications of your mobile applications and described a simple way to do so. For Internet protocols that operate in the clear, like Telnet, encryption is a must. Bearing in mind the need for host authentication and signed certificates, TLS/SSL provides a quick and easy way to transmit encrypted data using almost any Internet protocol. Even better, it's a standard part of the MIDP 2.0 platform, the device permitting, opening the door to a wide range of secure network applications running on mobile devices.

For More Information

The links in this article are repeated here:

About the Author

Michael Powers is Principal of mpowers LLC, a software consultancy for desktop and wireless platforms, and he has been working with Java technology in its various incarnations since its inception. His award-winning Piranha Pricecheck MIDlet is taking the world by storm, and is a free download from mpowers.net.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
If you would like a reply to your comment, please submit your email address:
Note: We may not respond to all submitted comments.