Digital Signatures With the Java ME SATSA API

   
By Bruce Hopkins, August 2009  

Let's say that you were building a mobile application for a financial institution, but in order to secure the application, you had to choose between one of these options:

  • Guaranteed data confidentiality, with no way for a third party to read the contents of the messages

    or
  • Guaranteed user identity, with 99.999% assurance that the person that you're dealing with is who he says that he is

Which would you choose?

This is a trick question, of course, because the answer is never clear-cut. For a software developer, security techniques like encryption, which provides data confidentiality, and digital signatures, which provide user identity, are like a hammer and a screwdriver: Each serves a vastly different purpose.

The purpose of this article is to briefly explain the differences between encryption and digital signatures and to show developers how to use the Java ME Security and Trust Services API (SATSA) to create digital signatures for mobile applications.

Comparison of Encryption and Digital Signatures

Deciding which security technique to use depends largely on the use case. Let's say that you want to transfer information from point A to point C, as shown in Figure 1.

 
Figure 1: Transmitting Data Over a Public Network Can Be Risky.
 
 

Encryption is cryptographic function that secures sensitive data — in transit or at rest — and ensures that the data can be understood by the intended recipient. One of its primary uses is when you want to get information from one point to another, and you want to ensure that the information stays confidential. Encryption is best suited to transferring sensitive information over a network. No matter what industry you're in — whether government, health care, financial services, education, or any other — you will deal with some form of sensitive information. For financial institutions, sensitive information would include things such as these:

  • User account numbers
    • Bank account numbers
    • Credit card numbers
  • Username-password pairs
  • Social security numbers
  • Account holder's personal information
    • Name
    • Address
    • Phone number
    • Age

For instance, if you are building a mobile application that allows a user to type in a credit card number for a sales transaction, you should definitely use an encryption algorithm to transmit the purchaser's credit card number securely from the mobile device to the back-end servers that will process the credit card information.

Conversely, a digital signature is a cryptographic function that provides the identity of the signer and guarantees the integrity of the signed artifact. Creating a digital signature is a two-step process. First, a secure hash of the content is generated, using a hashing algorithm. Second, the bytes from the secure hash are encrypted, which produces a cryptographically secured digital signature. Therefore, in some cases, the content is actually transmitted in clear text — unencrypted — because the identity of the sender is significantly more important than the content of the data. Let's examine a common use case where this fits.

One of the Best Use Cases for Digital Signatures: A Workflow Application

In a typical workflow scenario, the sensitivity of the data is superseded by the identity — and the roles — of the users. One of the most common workflow applications is a corporate payroll system. Figure 2 depicts the workflow for data coming in and out of a typical corporate payroll department.

 
Figure 2: The Workflow for a Typical Payroll Department.
 
 

For a payroll workflow scenario, the identity of the user is extremely important, but the content of the data is not necessarily so sensitive that it needs to remain private.

For instance, every employee must submit a timecard or timesheet with a breakdown of the hours that he or she spent on each project. This information is not necessarily sensitive. All of Bruce's team members know when he's working, so they all know what's on this timesheet. Additionally, everyone on his team should have very similar timecards.

However, the identity of the users of the timecard system is very important: Bruce should submit a timecard only for himself and not for anyone else. Additionally, Bruce's manager should be the only one who can approve or reject Bruce's timecard. You can image the chaos that would ensue if anyone could submit and approve — or reject — anyone else's timecard.

Digital signatures can not only identify the signer of the data, they have the additional benefit of ensuring the integrity of the signed artifact. So if employee Christine submits a timecard with a digital signature that showed 98.8 hours of work within a week, she cannot later claim that she really submitted a timecard with 89.8 hours, and that the network must have garbled two of the digits.

Part of the mechanism of a digital signature includes a secure hash to assure the individual who verifies the signature that the data was not modified in transit. So if you sign the message with "I love Java and puppies," and an attacker somehow changes the message to "I love puppies and Java," then the verification process will fail.

The Role of Digital Certificates for Digital Signatures

Many books have been written on the subject of computer security, and this article will not rehash their content. However, you should understand the importance of the role of a digital certificate for computer security.

A private key for signing content is simply an array of bytes. It does not contain an identity, and frankly it is unintelligible — from a human's perspective — from any other array of bytes.

A digital certificate, however, is a file that provides the identity of the certificate owner. If the certificate owner is a person, then the certificate includes the person's name, address, and company details. If the owner is a computer, then the certificate includes the computer's hostname and IP address. In both cases, part of the digital certificate also includes the private key of the certificate owner.

A digital certificate plays an important role in digital security because it is a single entity that ties together a PKI private key with the identity of the owner. In the case of the SATSA API and other security frameworks, the type of certificate that you'll be dealing with is an X509 certificate. Now, a digital certificate also provides information of the Certificate Authority, often abbreviated as CA, the entity that issued the certificate. The CA plays an important role because if you trust the CA, then you can trust the identity of the users that the CA has verified: They are who they say that they are.

Running the PaymentAuthorization MIDlet

The PaymentAuthorization MIDlet is a simple SATSA-PKI application that shows developers how to leverage the capabilities of the JSR 177 API to create a digital signature. In theory, a manager would use this application on her mobile device to approve the timecards of her employees.

The CMSMessageSignatureService class in the SATSA-PKI optional package can be used to sign either a String object or a byte array of data.

In this example, we're going to assume that the employees have already submitted their timecards into the payroll system, and these are ready to be approved by a manager. Within the PaymentAuthorization MIDlet application, the String of comma-separated values represents the data in the employee timecards. In order for the manager to pass the timecard to the payroll department, all she has to do is to approve or deny the timecard, which appends the decision to the comma-separated values. After the final String has been created, the data is signed. Listing 1 shows the full source code for the PaymentAuthorization MIDlet.

Listing 1. The PaymentAuthorization MIDlet
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.securityservice.CMSMessageSignatureService;
import javax.microedition.securityservice.CMSMessageSignatureServiceException;
import javax.microedition.io.file.FileConnection;
import javax.microedition.io.file.FileSystemRegistry;
import java.io.OutputStream;
import java.util.Enumeration;
import javax.microedition.io.Connector;

public class PaymentAuthorization extends MIDlet implements CommandListener {

    Display display = null;
    List employeeList = null;
    String[] employeeArray = {"Derrick Johnson, 40 hrs", "James Williams, 44 hrs", "Tirrell Payton, 42 hrs", "William Bean, 20 hrs"};
    Form progressForm = null;
    Command authCommand = null;
    Command denyCommand = null;
    Command exitCommand = null;
    String originalMessage = null;
    byte[] signedMessage = null;
    String signedMessageFile = "paymentAuthorization.dat";

    public PaymentAuthorization(){

        //
        // initialize the list of employees
        //
        employeeList = new List("Payment Authorization", List.IMPLICIT, employeeArray, null);

        employeeList.setCommandListener(this);

        //
        // initialize the commands
        //
        authCommand = new Command("Authorize", Command.OK, 0);
        denyCommand = new Command("Deny", Command.OK, 0);
        exitCommand = new Command("Exit", Command.EXIT, 1);

        employeeList.addCommand(authCommand);
        employeeList.addCommand(denyCommand);

        //
        // create the form to show the progress for signing
        //
        progressForm = new Form("Signing Progress");
        progressForm.addCommand(exitCommand);
        progressForm.setCommandListener(this);


    }

    public void startApp() {

        //
        // set the employee list as the first to display
        //
        display = Display.getDisplay(this);
        display.setCurrent(employeeList);
    }

    public void pauseApp() {
    }

    public void destroyApp(boolean unconditional) {
    }

    public void commandAction(Command command, Displayable d) {
        if (command == exitCommand) {
            destroyApp(true);
            notifyDestroyed();
        } else {

            display.setCurrent(progressForm);
            originalMessage = employeeArray[employeeList.getSelectedIndex()] + ", " + command.getLabel();

            new Thread() {
                    public void run() {
                        progressForm.append("Sign test started ...\n");
                        System.out.println("Sign test started...");
                        signMessage();
                        progressForm.append("Sign test finished.\n");
                        System.out.println("Sign test finished.");
                    }
           }.start();
        }

    }

    private void signMessage() {
        // String caName = new String("cn=ca_name,ou=ou_name,o=org_name,c=ie");
        String caName = "c=US,st=CA,l=Santa Clara,o=dummy CA,ou=JCT,cn=thehost";
        String[] caNames = new String[1];
        String userPrompt = "Please insert the proper security element ";

        caNames[0] = caName;

        try {

            // Generate a formatted signature that includes the content
            // that was signed in addition to the certificate.
            // Selection of the key is implicit in selection of the certificate,
            // which is selected through the caNames parameter.
            // If the appropriate key is not found in any of the
            // security elements present in the device, the implementation
            // may guide the user to insert an alternative security
            // element using the securityElementPrompt parameter.


            signedMessage = CMSMessageSignatureService.sign(originalMessage,
                    CMSMessageSignatureService.SIG_INCLUDE_CERTIFICATE |
                    CMSMessageSignatureService.SIG_INCLUDE_CONTENT, caNames, userPrompt);


            //
            // take the signature and create a file
            //
            //
            FileConnection fileConnection = null;
            OutputStream outputStream = null;
            try{
                Enumeration e = FileSystemRegistry.listRoots();

                String rootName = (String) e.nextElement ();

                fileConnection = (FileConnection)Connector.open("file:///" + rootName + signedMessageFile);


                if (fileConnection.exists() == false){
                    fileConnection.create();
                }
                outputStream = fileConnection.openOutputStream();
                outputStream.write(signedMessage);
                outputStream.flush();
                outputStream.close();
                fileConnection.close();
            } catch (Exception e){
                System.out.println("Error creating file");
                e.printStackTrace();
            }

        } catch (IllegalArgumentException iae) {
            // Perform error handling
            iae.printStackTrace();
        } catch (CMSMessageSignatureServiceException ce) {
            if (ce.getReason() == CMSMessageSignatureServiceException.CRYPTO_FORMAT_ERROR) {
                System.out.println("Error formatting signature.");
            } else {
                System.out.println(ce.getMessage());
            }
        } catch (Exception e) {
            System.out.println("Other exception: " + e);
        }
    }
}
       

Listing 1 includes the certificate as well as the content in the final signed message. This line of code accomplishes that feat:

signedMessage = CMSMessageSignatureService.sign(originalMessage,
                    CMSMessageSignatureService.SIG_INCLUDE_CERTIFICATE |
                    CMSMessageSignatureService.SIG_INCLUDE_CONTENT, caNames, userPrompt);
       

Additionally, you should note that the final signature is a byte array of data, so you have only a few ways to get the signed data off the mobile device. In a true production scenario, the digital signature will most likely be sent to a remote server over HTTP. This example, however, uses the JSR 75 File Connection APIs to write the signed data to the file paymentAuthorization.dat. By creating a local file on the development machine, you do away with the need to set up an HTTP server to receive the signed data and try to pipe it to a file on the server side.

To run the application, you must first install the Java ME SDK 3.0, which provides the necessary tools to run SATSA applications. One of those tools is the JavaCard C Reference emulator, known as the cref tool, which allows the Java ME SDK to emulate a security element — for example, a SIM smart card — of a mobile phone.

The Java ME SDK 3.0 includes all the tools that you will need to run a basic application that provides a digital signature without having to create X509 certificates or to set up a Certificate Authority (CA). In order for the PaymentAuthorization MIDlet to find its private key to sign the timecard for each employee in this example, start the cref tool before you try to run the PaymentAuthorization MIDlet.

Here's how to start cref from the command line, with Java ME SDK installed at C:\Java_ME_platform_SDK_3.0 on your computer:

C:\Java_ME_platform_SDK_3.0\bin\cref -i apps\SATSADemos\sat.eeprom
       

After the cref has begun working, you should see the output shown in Listing 2.

Listing 2. The Initial Output of the cref Command at Startup
Java Card 2.2.1 C Reference Implementation Simulator (version 0.41)
32-bit Address Space implementation - with cryptography support
Copyright 2003 Sun Microsystems, Inc. All rights reserved.

Memory configuration
        Type    Base    Size    Max Addr
        RAM     0x0     0x800   0x7ff
        ROM     0x2000  0xb000  0xcfff
        E2P     0x10020 0xffe0  0x1ffff

        ROM Mask size =                 0x8e35 =        36405 bytes
        Highest ROM address in mask =   0xae34 =        44596 bytes
        Space available in ROM =        0x21cb =        8651 bytes
EEPROM (0xffe0 bytes) restored from file "apps\SATSADemos\sat.eeprom"
Using a pre-initialized Mask
       

Now that the cref tool has been started, you have everything you need to digitally sign the employee timecards. Figure 3 shows the application in action.

 
Figure 3: The Initial Screen for the PaymentAuthorization MIDlet.
 
 

The PaymentAuthorization MIDlet processes the decision of the manager to accept or reject the employee's timecard. Before the signature process takes place, the JVM* prompts the user for the personal identification number (PIN) to the private key, as shown in Figure 4.

 
Figure 4: The JVM Prompts the User for the PIN to the Private Key.
 
 

Note that if you are still running the cref tool, as specified earlier, you must use the PIN code of 2345 to work with the emulated security element for the SATSA demos that are included in the Java ME SDK 3.0. The final signed data file will be placed in the virtual root of your application instance provided by the Java ME SDK 3.0. If you want to use a different PIN for your own application, you must set up your own CA and import your certificates, which is outside of the scope of this article.

How Can You Verify the SATSA Signature?

You now have the tools and code necessary to create a digital signature using the SATSA API. But how can you or anyone else verify the signature? The SATSA API generates digital signatures in the RFC 3852 cryptographic message syntax (CMS) format, so you might expect that a SATSA-enabled device should be able to verify SATSA signatures. But that is not the case.

The SATSA API does not have the capability to verify the signatures that it creates. Additionally, the Java SE 6 API itself has the ability to create and verify digital signatures, but it cannot verify a digital signature in CMS format. Therefore, in order to verify a SATSA signature, you must use a third-party library, such as the Bouncy Castle Crypto API. Listing 3 shows you how to use the BouncyCastle API to verify a SATSA signature in CMS format.

Listing 3. Use of a Third-Party Library to Verify a SATSA Signature: BouncyCastle API.
    public static void main(String[] args) throws IOException {

        Security.addProvider(new BouncyCastleProvider());
        try{
                CMSSignedData cmsSignedData = getCMSSignedDataFromFile(new File("auth_signature.data"));
                System.out.println("Is this valid: " + isValid(cmsSignedData, ca_cert));
        } catch (Exception e){
                System.out.println("error creating CMS file");
                e.printStackTrace();
        }

    }


    /**
     * Return a boolean array representing keyUsage with digitalSignature set.
     */
    static boolean[] getKeyUsageForSignature(){
        boolean[] val = new boolean[9];

        val[0] = true;

        return val;
    }

    /**
     * Take a CMS SignedData message and a trust anchor and determine if
     * the message is signed with a valid signature from an end
     * entity certificate recognized by the trust anchor rootCert.
     */
    public static boolean isValid(CMSSignedData signedData, X509Certificate rootCert)throws Exception{

        CertStore certsAndCRLs = signedData.getCertificatesAndCRLs("Collection", "BC");
        SignerInformationStore signers = signedData.getSignerInfos();
        Iterator it = signers.getSigners().iterator();

        if (it.hasNext()){

            SignerInformation         signer = (SignerInformation)it.next();
            X509CertSelector          signerConstraints = signer.getSID();

            signerConstraints.setKeyUsage(getKeyUsageForSignature());

            PKIXCertPathBuilderResult result = Utils.buildPath(rootCert, signer.getSID(), certsAndCRLs);

            return signer.verify(result.getPublicKey(), "BC");

        }

        return false;
    }



    public static CMSSignedData  getCMSSignedDataFromFile(File file) throws IOException {
        InputStream is = new FileInputStream(file);
        CMSSignedData cms = null;

        try {

                cms = new CMSSignedData(is);

        } catch (Exception e){
                System.out.println("could not create cms file");
                e.printStackTrace();
        }

        return cms;
    }
       

Conclusion

Knowing when and how to use the proper security technique is a skill that every enterprising developer must have. This article briefly explained the difference between encryption and digital signatures. As you have seen, encryption is not the solution to every security problem, especially because encryption does not provide the identity of any of the users of the system. Digital signatures, on the other hand, provide the identity of the signer, which is extremely important in workflow applications, such a payroll system. Finally, this article provided you with a complete example that shows how to use the SATSA-PKI API and the tools within the Java ME SDK 3.0 to digitally sign data within a payroll workflow system.

* As used on this web site, the terms "Java Virtual Machine" and "JVM" mean a virtual machine for the Java platform.

For More Information

Java ME SDK 3.0
JSR 75: PDA Optional Packages for the J2ME Platform
JSR 177: Security and Trust Services API for J2ME
JSR 177 — Security and Trust Services API for J2ME 1.0
Bouncy Castle Crypto API

Rate This Article

 
 

Discussion

We welcome your participation in our community. Please keep your comments civil and on point. You can optionally provide your email address to be notified of replies—your information is not used for any other purpose. By submitting a comment, you agree to these Terms of Use.