JavaCard: The execution environment you didn’t know you were using
2020-05-25 18:07:20Vasilios Mavroudis and Petr Svenda
This is the story of the most popular execution environment, its shortcomings, and how open source and hacking saved the day.
According to recent revelations, the MINIX operating system is embedded in the Management Engine of all Intel CPUs released after 2015. A side-effect of this is that MINIX became known as the most widespread operating system in the world almost overnight. However, in the last decade another tiny OS has silently pushed itself into even more devices around the world while remaining unknown to most: JavaCard1.
With more than six billion JavaCards sold last year, and approximately 20 billion estimated to have been purchased in total, JavaCard is the winner no one knows about. The execution environment was designed in 1996 for devices with limited memory and processing capabilities and was the first smartcard platform to give developers the ability to execute the same applet on cards produced by different manufacturers. This was a breakthrough for the industry that established JavaCard as the default platform for applications in need of a secure, tamper-proof element.
A malfunctioning operating system
An operating system is much more than the sum of its source code: it’s also the ecosystem built around it, including the specifications, support, and most importantly the application developers and the user community.
For JavaCard, the specification part is handled formally by Oracle and Java Card Forum who make periodical releases of the platform’s virtual machine (JCVM) specification, runtime library (JCRL) and application programming interface (JC API). All these contribute towards homogeneity between cards from different manufacturers; aiming to ensure applet interoperability and a minimum level of support for basic cryptographic algorithms - at least in theory. In practice, our research has shown that no product in the market implements JC API completely, and different cards support different sets of features. This severely hinders the interoperability of applications and constrains developers within the limited subset of JavaCard features supported by most manufacturers. Developers who choose to use all the features provided by a specific card will, with high likelihood, abolish the interoperability of their applets. Furthermore, some of those specifications are also inadvertently limiting the scope of the platform. For instance, the API specification that lists all the calls to be potentially available to smart card applications ended up acting as an evolutionary bottleneck. This is due to:
Approximately three-year-long API revision cycles that severely delay support for newer cryptographic algorithms (the last API revision was released in 2015).
More complex cryptographic operations (especially asymmetric cryptography) requiring design and production of dedicated hardware accelerators to actually support newly added cryptographic algorithms.
The business model is geared towards the large corporations. Hence, newer cards are available only to those buying in large quantities while smaller development houses and researchers are forced to work with five years old, or even older, cards.
Overall, while the JavaCard OS has managed to hold a very large chunk of the secure hardware market, its inflexibility and inconsistencies increasingly prevent its adoption in novel use cases.
All these issues have not gone unnoticed by the manufacturers, who attempt to address them through proprietary APIs. As the name implies, these APIs are specific to each manufacturer and are designed to extend the native JavaCard functionality exposed to developers. It is noteworthy that the hardware capabilities of the smartcards remain usually the same, it is just that these APIs make more of the card’s capabilities directly available to developers.
In particular, developers may use primitive cryptographic operations found in those APIs to realize new unsupported algorithms, thus overcoming the slow evolution of the standard API. For instance, while the standard JC API provides only a high-level ECDSA signature operation, proprietary APIs directly expose the underlying elliptic curve operations.
As there is no common standard, each manufacturer exposes a different set of calls that either trigger functions found in the JavaCard Specification or invoke completely new algorithms that aim to support more modern applications.
Proprietary APIs may look like a promising solution at first glance, but in practice lead to multiple issues. Their heterogeneity makes it impossible for an applet to be compatible with smart cards from multiple manufacturers, leading to a specific platform lock-in. Moreover, only specific customers (e.g., large companies placing substantial orders) can access and use these APIs (after signing a non-disclosure agreement - NDA), while small/medium-size development houses and research labs are not allowed to. This makes JavaCard very hostile towards the open-source development and fostering of innovative ideas.
The OpenCrypto Project
JavaCard by itself is not open source, and neither are the great majority of applications currently used by billions of users. This is partially attributed to the restrictions imposed by the APIs and NDAs signed by most of the major corporations using JavaCard. Even in the rare case where researchers or smaller developers gain access to a proprietary API, the NDA makes it impossible for them to share their prototypes or source code for others to reproduce their results or extend the code base.
To partially mitigate this problem and enable the JavaCard OS to support newer applications, we started the OpenCrypto Project. The project’s main goal is to give JavaCard the flexibility that it has been lacking. The first step is a cryptographic library that provides all necessary cryptographic primitives (e.g., Big Numbers, Elliptic Curve Points) for the development of new algorithms.
Developers can now implement new algorithms that are not natively supported by the OS, without proprietary solutions or NDA. Additionally, the crypto library realises functionality that, even though it is outlined in the specification, is not found in any commercial products (e.g., Integers). Here is an example implementation of a multiparty computation protocol utilising cryptographic operations which do not appear in the standard JavaCard specification. Developers and researchers can use it to study, prototype and release products with no restrictions. Once a prototype has been developed and tested, developers may still opt to use a proprietary API which would provide better performance and better side-channel resistance.
How to implement modern crypto in your parent’s first computer (but with less RAM and disk space)?
The largest data structures commonly available in JavaCard are byte and short (i.e., 2 bytes), with int supported only infrequently. Based on byte and short primitive types, we built a BigNumber class that enabled us to store the very large numbers used for crypto. While storing was a great first step, with only ~40MHz under the hood, operating on those truly large numbers (e.g., 256-bits long) took ages to compute and frequently resulted in time-outs or crashes.
That’s where we turned our attention to the crypto coprocessor. In general, coprocessors are specialised units optimised to excel in few specific tasks. In our case, the coprocessors found in smart cards are almost always optimised to perform cryptographic operations. The downside is that the coprocessor is not directly accessible to developers who were not given proprietary access by a manufacturer. Instead, only predefined high-level function calls (i.e., RSA encryption) are allowed. This hinders the implementation of newer crypto algorithms and protocols (e.g., group signatures) that are not yet included in the JC API, as access to lower-level operations (e.g., multiplication of large numbers, Elliptic Curve points operations) is required for that. Those low-level operations are indeed supported by the coprocessor but are carefully locked out of the developers’ reach – unless an NDA is signed with the manufacturer.
Without going into the technical details, given the manufacturer’s lemons, we made the lemonade. In other words, we managed to re-realise the primitive cryptographic operations by carefully tunneling computations through the few available high-level coprocessor calls. For example, to realise modular exponentiation of a BigInteger we used the RSA-encryption API call taking unpadded data with the specifically crafted public key. Other operations (especially with elliptic curve points) were more complicated to implement and required a combination of multiple API calls and intermediate computation. For the technically curious, the full code is available.
The two most widespread OSes (JavaCard and Intel’s MINIX) are surrounded by secrecy and are fully accessible only to a select few. Their main feature is working reliably and flawlessly so that everyone can ignore their existence. However, as new use cases emerge (e.g., Internet of Things), and existing ones evolve to accommodate new requirements, the current centrally controlled development model needs to be replaced by a more flexible one. Doing so will not only open and enlarge the development ecosystem, but also enable fresh and progressive ideas to develop.
1 While JavaCard is technically not an OS in the standard sense (smart cards do have their own proprietary OSes), in practice it provides very similar functionality with modern embedded OSes. For instance, unless granted by the vendor, app developers are strictly limited within the JavaCard runtime environment; this distinguishes JavaCard from e.g, the classic Java VM where developers can also execute native applications in addition to those executed in the JVM.
Vasilios Mavroudis is a doctoral researcher in the Information Security Group at University College London. His research interests include the security and privacy aspects of emerging technologies and systems.
Petr Svenda is a computer security researcher, lecturer and active member of the Centre for Research on Cryptography and Security at Masaryk University in Brno, Czech Republic. His main research areas are cryptographic protocols for limited devices, analysis and use of secure hardware and randomness assessment and entropy extraction.
Java Card is an open standard from Sun Microsystems for a smart card developmentplatform. Smart cards created using the Java Card platform have Javaapplets stored on them. The applets can be added to or changed after the card is issued.
There are two basic types of smart cards. The memory smart card is the familiar removable memory device; it usually features read and write capabilities and perhaps security features. The more complex version, the processor smart card, is a very small and extremely portable computing device that could be carried in your wallet. Java-based smart cards belong to the latter category. They store data on an integrated microprocessor chip. Applets are loaded into the memory of the microprocessor and run by the Java Virtual Machine. Similarly to MULTOS, another smart card development technology, Java Card enables multiple application programs to be installed and coexist independently. Individual applets are protected by a firewall to preserve their integrity and prevent tampering. Applications can be updated dynamically.
In the United States, the Department of Defense, Visa, and American Express are among the organizations creating Java Card-based applications.