Skip Headers
Oracle® Java ME Embedded Developer's Guide
Release 8.1
E52611-02
  Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

8 Working with Java ME Encryption

This chapter introduces the encryption functionality available to the Java ME Embedded programmer with the Oracle Java ME Embedded 8.1 release.

8.1 Connecting to an SSL Server

Creating a connection to an SSL server only requires the programmer to include an appropriate ConnectionOption object in the call to Connector.open(). This example requires the following hardware:

Table 8-1 Hardware for Example 1-1

Hardware Where to Obtain

Raspberry Pi 512 MB Rev B

Various third-party sellers


In this example, we use the Oracle Java ME Embedded runtime to connect to a server on the network that is running SSLv3 on port 443. Note that this example requires the user to configure a web server that will accept an incoming connection on that port and uses the proper protocol and is properly signed by a valid certificate authority. After this is setup, the value of the sTestServerAddr variable should be changed accordingly. Example 8-1 shows the source code.


Note:

At the time of release, Oracle Java ME Embedded 8.1 has removed support for SSLv3 due to a widely-publicized security vulnerability. However, the source code example is applicable to other forms of transport-layer security included with Oracle Java ME Embedded 8.1.

Example 8-1 Connecting to an SSL Server

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.ConnectionOption;
import javax.microedition.io.Connector;
import javax.microedition.io.SecureConnection;
import javax.microedition.midlet.MIDlet;


public class SSLConnect extends MIDlet {

    @Override
    public void startApp() {

        SecureConnection sc;
        ConnectionOption<String> protocol;
        InputStream is;
        OutputStream os;
        DataInputStream dis;
        DataOutputStream dos;
        
        String sTestServerAddr = "example.com:443";
        
        try {
            
            protocol = new ConnectionOption<>("Protocol", "SSLv3");
            sc = (SecureConnection) Connector.open("ssl://" +
                sTestServerAddr, protocol);
         
            System.out.println("Connection successful to:");
            System.out.println("Address: " + sc.getAddress());
            System.out.println("Port: " + sc.getPort());
            System.out.println("Cipher Suite: " +
                sc.getSecurityInfo().getCipherSuite());
            System.out.println("Protocol Name: " +
                sc.getSecurityInfo().getProtocolName());
            System.out.println("Protocol Version: " +
                sc.getSecurityInfo().getProtocolVersion());
 
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void pauseApp() {
    }

    @Override
    public void destroyApp(boolean unconditional) {
    }

}

The following permissions must be added to the Application Descriptor of the IMlet so that it will execute without any security exceptions from the Oracle Java ME Embedded runtime.

Table 8-2 Permissions for Example 4-1

Permission Device

javax.microedition.io.SSLProtocolPermission

ssl://:*

javax.microedition.io.SSLProtocolPermission

ssl://*:*

javax.microedition.io.SocketProtocolPermission

socket://*:*


Note that if you're using an IDE such as NetBeans as the development environment, you will need to access the project properties of the project and set API permissions under the application descriptor, as shown in Figure 8-1.

Figure 8-1 API Permissions in the Project Properties Dialog in NetBeans

Description of Figure 8-1 follows
Description of "Figure 8-1 API Permissions in the Project Properties Dialog in NetBeans"


Tip:

If your server does not currently use a certificate from a signed certificate authority (CA), you can import a self-signed certificate to the Java ME Embedded device. Locate the MEKeytool executable in the bin directory of the Oracle Java ME Embedded SDK distribution, and enter the following command using a Windows command prompt.
C:\SDK\bin> mekeytool.exe -import -Xdevice:EmbeddedExternalDevice1 -keystore myCert.crt

This command will connect to the keystore on the embedded device currently recognized by the Device Manager as "EmbeddedExternalDevice1" and install the certificate with the filename myCert.crt. Note that this certificate must be identical to the one residing on the server that is authenticating SSL/TLS connections, or the Java embedded runtime will throw a javax.microedition.pki.CertificateException when attempting a secure connection. See Appendix D for more information on using the MEKeyTool utility.


After running the application, you should see output that identifies a successful connection to the server at the address and port specified. The program will then output the address and port, as well as the security connection parameters that were used to make the connection.

Connection successful to:Address: 192.168.1.125Port: 443Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHAProtocol Name: TLSProtocol Version: 3.1

8.2 Authenticating an SSL Server

In this example, we expand on the ConnectionOption objects to provide an option to authenticate an HTTPS server. As with the previous example, the value of the serverAddr variable should be modified to point to a properly configured server. Example 8-2 shows the source code.


Note:

At the time of release, Oracle Java ME Embedded 8.1 has removed support for SSLv3 due to a widely-publicized security vulnerability. However, the source code example is applicable to other forms of transport-layer security included with Oracle Java ME Embedded 8.1.

Example 8-2 Authenticating an SSL Server

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.microedition.io.ConnectionOption;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.HttpsConnection;
import javax.microedition.midlet.MIDlet;
import javax.microedition.rms.RecordStore;
 
/**
public class AuthenticateServer extends MIDlet {
 
    public static final int PASSED = 1;
    public static final int FAILED = -1;
    
    @Override
    public void startApp() {
 
        String serverAddr = "https://example.com:443";
 
        HttpsConnection hc;
        ConnectionOption<String> auth;
        ConnectionOption<String> protocol;
        int response = HttpConnection.HTTP_NOT_FOUND;
 
        try {
 
            auth = new ConnectionOption<>("AuthenticateServer", "TRUE");
            protocol = new ConnectionOption<>("Protocol", "SSLv3");
 
            hc = (HttpsConnection) Connector.open(serverAddr,
                Connector.READ_WRITE, auth, protocol);
            response = sendReqAndgetResp(hc); //request GET
 
            if (response == PASSED) {
                System.out.println("Pass");
            } else {
                System.out.println("Failed");
            }
 
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (SecurityException ex) {
            ex.printStackTrace();
        } catch (RuntimeException ex) {
            ex.printStackTrace();
        }
    }
 
    @Override
    public void destroyApp(boolean unconditional) {
    }
 
    private int sendReqAndgetResp(HttpsConnection hc) {
        
        int resCode = -1;
        boolean pass = true;
 
        OutputStream os;
 
        try {
            ((HttpsConnection) hc).setRequestMethod(HttpConnection.GET);
            resCode = ((HttpsConnection) hc).getResponseCode();
            System.out.println("Response code is: " + resCode);
            
            if (resCode == HttpConnection.HTTP_OK) {
                return PASSED;
            } else {
                return FAILED;
            }
            
        } catch (IOException ex) {
            ex.printStackTrace();
            return FAILED;
        } finally {
            try {
                hc.close();
            } catch (IOException ex) {
            }         
        }
    }
}

The following permissions must be added to the Application Descriptor of the IMlet. Note that because we are using HTTPS, we require the HTTPS protocol permission, even through the implementing protocol we requested for HTTPS (SSLv3) is the same.

Table 8-3 Permissions for Example 4-2

Permission Device

javax.microedition.io.HTTPSProtocolPermission

https://*:*


This example is similar to Example 8-1. Here, however, we create an HTTPS connection with requests and responses (instead of a direct SSL connection). An additional ConnectionOption object also instructs the Java ME example to authenticate the server.

auth = new ConnectionOption<>("AuthenticateServer", "TRUE");

Enabling this option will verify that the server certificate is valid and has been signed by a valid certificate authority, as well as performing a number of verification steps against the data presented by the certificate. If the test is successful, you should see output that identifies a connection to the HTTPS server at the address and port specified.

Pass

8.3 Accessing the Keystore

Each Java ME Embedded implementation has one or more keystores, typically located under the appdb/certs directory. There is one keystore for each application privilege level (such as untrusted or operator). In order to programmatically access the keystore, use the classes in the com.oracle.crypto.keystore package.

Example 8-3 shows source code used to create five certificates, store them in the keystore, and then iterate over the contents of the keystore when completed.

Example 8-3 Accessing the Embedded Keystore

import java.io.DataInputStream;
import com.oracle.crypto.cert.X509Certificate;
import com.oracle.crypto.cert.X509CertificateBuilder;
import com.oracle.crypto.keypair.KeyPair;
import com.oracle.crypto.keypair.KeyPairGenerator;
import com.oracle.crypto.keypair.PrivateKey;
import com.oracle.crypto.keypair.spec.RSAKeyGenParameterSpec;
import com.oracle.crypto.keystore.KeyStore;
import com.oracle.crypto.keystore.KeyStoreEntry;
import com.oracle.crypto.keystore.KeyStoreException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.microedition.midlet.MIDlet;
 

public class GenerateKeystore extends MIDlet {
 
    @Override
    public void startApp() {
 
        try {
 
            HashMap<String, KeyStoreEntry> shadow = new HashMap();
            KeyStore ks = KeyStore.getInstance(KeyStore.STORAGE.CLIENT);
 
            for (int i = 0; i < 5; i++) {
                
                KeyStoreEntry kse = generateRandomKeyStoreEntry();
                System.out.println("Add entry with certificate serial number: " +
                        kse.getCertificate().getSerialNumber());
                ks.addEntry(kse);
 
            }
 
            List<KeyStoreEntry> list = ks.getEntries();
            Iterator<KeyStoreEntry> iter = list.iterator();
 
            while (iter.hasNext()) {
                KeyStoreEntry kse = iter.next();
                String subject = kse.getCertificate().getSubject();
                System.out.println("Certificate Subject: " + subject);
 
                PrivateKey entryKey = kse.getPrivateKey();
                byte[] entryEncoded = entryKey.getEncoded();
 
                System.out.println("Private Key: " + entryEncoded.toString());
 
            }
 
        } catch (SecurityException ex) {
            //  Handle exception
        } catch (KeyStoreException ex) {
            //  Handle exception
        }
 
    }
 
    @Override
    public void destroyApp(boolean unconditional) {
    }
 
    private KeyStoreEntry generateRandomKeyStoreEntry() {
 
        KeyStoreEntry entry = null;
        try {
 
            AlgorithmParameterSpec param;
            param = new RSAKeyGenParameterSpec(512, 3);
 
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(param);
            KeyPair kp = kpg.generateKeyPair();
 
            int serialNumber = (int)(Math.random() * 1000000);
 
            System.out.println("Create X509 Certificate serial: " + serialNumber);
 
            X509CertificateBuilder builder = new X509CertificateBuilder(kp);
            builder.setSerialNumber("" + serialNumber);
            builder.setSubject("C=JP;ST=NE;L=Menlo;O=Oracle;OU=Java;CN=Test." +
                serialNumber);
            builder.setValidityInDays(365);
            X509Certificate cert = builder.create();
 
            entry = new KeyStoreEntry(cert, kp.getPrivate(), "test");
 
        } catch (Throwable ex) {
            ex.printStackTrace();
        }
        return entry;
    }
}

The following permissions must be added to the Application Descriptor of the IMlet to access the keystore on the Java ME Embedded device.

Table 8-4 Permissions for Example 4-3

Permission Device

com.oracle.crypto.keystore.KeyStorePermission

client_only


This example will access the local keystore on the embedded board (client) with the following call:

KeyStore ks = KeyStore.getInstance(KeyStore.STORAGE.CLIENT);

Note that the keystore that is accessed will depend on the trust level of the application. If the Java ME embedded application is not signed, it will fall into the untrusted security domain by default.

We can access the keystore similar to accessing it with the Java SE environment. First, we create a KeyStoreEntry object and populate it with a certificate. This is, in turn, added to the embedded keystore via a simple loop and iterated over later in the program. Here is the output after running the program:

Creating X509 Certificate with serial number: 798364Add keystore entry with certificate serial number: 4F:53:40Creating X509 Certificate with serial number: 67079Add keystore entry with certificate serial number: 43:07:09Creating X509 Certificate with serial number: 723418Add keystore entry with certificate serial number: 48:22:12Creating X509 Certificate with serial number: 792956Add keystore entry with certificate serial number: 4F:1D:38Creating X509 Certificate with serial number: 661145Add keystore entry with certificate serial number: 42:0B:2D

Certificate Subject: C=JP,ST=NE,L=Menlo,O=Oracle,OU=Java,CN=Test.798364Private Key: [B@fcd4cfc2Certificate Subject: C=JP,ST=NE,L=Menlo,O=Oracle,OU=Java,CN=Test.67079Private Key: [B@1c1cc1a5Certificate Subject: C=JP,ST=NE,L=Menlo,O=Oracle,OU=Java,CN=Test.723418Private Key: [B@e854b14cCertificate Subject: C=JP,ST=NE,L=Menlo,O=Oracle,OU=Java,CN=Test.792956Private Key: [B@1d69c567Certificate Subject: C=JP,ST=NE,L=Menlo,O=Oracle,OU=Java,CN=Test.661145Private Key: [B@1a5796e6

8.4 Configuring the Board as a Secure Server

The Java ME Embedded binary contains functionality that allows an embedded board to function as a server using secure protocols. The functionality is identical to the configuration of a Java SE server.

Example 8-4 shows source code used to setup the embedded board as a server.


Note:

At the time of release, Oracle Java ME Embedded 8.1 has removed support for SSLv3 due to a widely-publicized security vulnerability. However, the source code example is applicable to other forms of transport-layer security included with Oracle Java ME Embedded 8.1.

Example 8-4 Server-Side Code

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.microedition.io.ConnectionOption;
import javax.microedition.io.Connector;
import javax.microedition.io.SecureConnection;
import javax.microedition.io.SecureServerConnection;
import javax.microedition.midlet.MIDlet;
 
public class EmbeddedServer extends MIDlet {
 
    @Override
    public void startApp() {
 
        String PORT = "10005";
 
        SecureServerConnection ssc = null;
        ConnectionOption<String> protocol = null;
 
        try {
 
            protocol = new ConnectionOption<>("Protocol", "SSLv3");
            ssc = (SecureServerConnection) Connector.open("ssl://:"+PORT,
                protocol);
 
            System.out.println("Connection listening on:");
            System.out.println("Address: " + ssc.getLocalAddress());
            System.out.println("Port: " + ssc.getLocalPort());
 
            ssc.acceptAndOpen();
 
            System.out.println("Connection made!");
 
        } catch (SecurityException ex) {
            ex.printStackTrace();
        } catch (RuntimeException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
 
    @Override
    public void destroyApp(boolean unconditional) {
    }
}

The following permissions must be added to the Application Descriptor of the IMlet to access the keystore on the Java ME Embedded device.

Table 8-5 Permissions for Example 4-3

Permission Device

javax.microedition.io.SSLProtocolPermission

ssl://*:*

javax.microedition.io.SocketProtocolPermission

socket://*:*


This example uses a SecureServerConnection object, which creates a socket at port 10005 using the SSL protocol. It is essential to include the following line as well:

ssc.acceptAndOpen();

Without this line, the secure socket will never accept an incoming connection, and any attempt to make a connection will result in a runtime exception. Note that a call to this method will block until a successful connection is made.

As with the previous examples, the Java ME Embedded keystore must have a valid server certificate for the trust-level that the application is running under, which will be validated upon any secure connection. If the certificate is absent, or is not valid, an exception will be thrown on the server.

The client-side code to make the connection is nearly identical to Example 8-1, with a slight change to the port and the protocol. A successful connection should output the following:

Address: 192.168.1.80
Port: 10005
Connection made!