How can I update a Java Card applet that contains data that need to be preserved across versions? As best as I can tell updating an applet is done by deleting it and then installing the new version, which seems like it would also delete any persistent data associated with the app.
As a concrete example, suppose I was writing an authentication and encryption applet. Version 1 of the applet would generate a key protected by the hardware on installation, and support signing messages, but not encrypting them. Suppose I then wanted to release a version 2 that also supported encryption, and could use the keys created by version 1. What would I need to do in version 1 and 2 in order to make that possible?
I'm open to solutions that use GlobalPlatform mechanics in addition to pure Java Card.
You need a second applet which owns all objects you want to preserve across re-installation of first applet. Let's call them Storage applet and Worker applet.
This means that every time a Worker applet needs to use resources from Storage applet it has to invoke Shareable interface. There is a penalty in code size, code maintainability and a penalty in speed. I can not think of another way to do this in Java Card or Global Platform.
You can't.
Updating an application package while preserving the data associated with any applet instantiated from that package is not possible on current JavaCard smartcards.
For one, this has a rather simple technical reason:
Applets are Java (Card) objects instantiated from classes in the code base of the application package. Updating the code base would change the structure of classes and, consequently, the already instantiated applet objects would no longer match their class definitions. As a result, whenever an applet class in the application package changes, this also means that the respective applet instance needs to be re-created.
Since all applet data is, itself, organized as Java (Card) objects (such as objects instantiated from user-defined classes, arrays, or primitive type fields that are stored as direct or indirect attributes of the applet instance, the applet instance is the root element1 of all its associated data. Consequently, the necessity to delete and re-create that root instance, also means that data stemming from that root element is deleted and re-initialized.
Of cource, this could be overcome by making applets (and all child objects storing the applet data) serializable. That way, an applet could be serialized to an auxilliary storage area before updating its code base. After the update, the applet instance (and its object hierarchy) could then be re-created by de-serializing that data. However, allowing this would have a sever security implication: Any managing instance could serialize (and, in the worst case, extract) that data.
This brings me to the second reason: In my opinion (though I was unable to find any authoritive ressource on this), a central design principle of the Java Card platform and smartcards in general is to prevent extraction of sensitive data.
Consider the following example: You have an applet for digital signing (e.g. PIV, OpenPGP, or simply the applet you described in your question). The purpose of this applet is to securely store the secret key on a smartcard chip (dedicated hardware with protection features inhibiting physical extraction of the key material even if an attacker gains access to the physical card/chip). As a consequence, the applet securely generates its private key material on-chip. The secret private key may then be used for signing (and/or decryption), but it should never be allowed to leave the card (since this would open up for key/card duplication, keys leaking to attackers, etc.)
Now imagine, that the smartcard runtime environment allows serialization of the applet data including the secret private key. Even if the card would not provide any means to directly extract that serialized data, simply consider an attacker writing a new applet that has exactly the same structure as your own applet, except that it provides one additional method to extract the key material from the card. The attacker now creates an application package that indicates it is an update to your existing applet. Further assume that the attacker is able to load that application package on the card. Now the attacker is able to update your applet and to break you original design goal (to make it impossible to extract the key from the card).
The design priciple that overwriting an existing application/applet requires to erase the existing applet and all its data is also (somewhat) manifested in both the GlobalPlatform Card specification and the Java Card Runtime specification:
GlobalPlatform Card Specification, Version 2.3, Oct. 2015:
"Check that the AID of the Load File is not already present in the GlobalPlatform Registry as an Executable Load File or Application."
"Check that the Application AID [...] is not already present in the GlobalPlatform Registry as an Application or Executable Load File"
Java Card 3 Platform, Runtime Environment Specification, Classic Edition, Version 3.0.4, Sept. 2011:
"The Java Card RE shall guarantee that an applet will not be deemed successfully installed in the following cases:
- The applet package as identified by the package AID is already resident on the card.
- The applet package contains an applet with the same Java Card platform name as that of another applet already resident on the card."
Moreover, the the specification makes clear that applet removal must remove all objects owned by the applet instance:
"Applet instance deletion involves the removal of the applet object instance and the objects owned by the applet instance and associated Java Card RE structures."
Nevertheless, sometimes there might be valid reasons to make parts of an application updatable without wiping information such as secret keys, and there are some ways to overcome this:
If you consider patch-/upgradability as a design goal from the beginning, you would certainly be able to design your application in a way that parts of it may be upgraded without losing associated data. You would typically split your application into multiple application packages that contain the different parts of your application functionality (also cf. Shuckey's answer). In the simplest form, one applet would contain and manage all the business logic and another applet (it needs to be in a separate application package through) is responsible for storing sensitive persistable data. You could then use shareable interface to access the data stored in the data storage applet from the business logic applet.
However, you would certainly want to carefully craft the interface between the two instances. For example you would definitely not want to pass secret private keys around directly. Instead you would only want to share an interface to perform signing/decryption operations on data passed from the business logic applet to the data storage applet. Otherwise, the same extraction issues as indicated above would arise.
1) This is not necessarily always true since data may (technically) be stored in static fields. In that case, the application package would be the root of these elements. However, doing this has a severe impact on security since access to static fields is not protected by applet isolation/the applet firewall. Cf. Java Card 3 Platform, Runtime Environment Specification, Classic Edition, Version 3.0.4, Sept. 2011, sect. 6.1.6:
"There is no runtime context check that can be performed when a class static field is accessed."
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With