Applet Development
This section describes the development environment and architecture of the OpenFIPS201 applet.
1 Contents
- 1 2 Building OpenFIPS201
- 2 3 Applet Architecture
- 2.1 3.1 Component Hierarchy
- 2.1.1 3.1.1 Key Role
- 2.1.2 3.1.2 Key Attributes
- 2.2 3.2 Applet Lifecycle
- 2.3 3.3 Development Principles
- 2.3.1 3.3.1 Private-Package Class Declarations
- 2.3.2 3.3.2 Exception-based Error Handling
- 2.3.3 3.3.3 Object Locking
- 2.3.4 3.3.4 Early Initialisation - Critical Data
- 2.3.5 3.3.5 Lazy Initialisation - Filesystem and Key Store
- 2.3.6 3.3.6 Defined Cryptographic Boundary
- 2.3.7 3.3.7 Optimised File Allocation Table
- 2.3.8 3.3.8 Approved Algorithms
- 2.3.9 3.3.9 Critical Security Parameter (CSP) Management
- 2.3.10 3.3.10 No ‘Roll Your Own’ Crypto
- 2.1 3.1 Component Hierarchy
- 3 4 Environment - Java Card
- 4 5 Environment - Global Platform
- 5 6 Applet Interoperability Testing
2 Building OpenFIPS201
2.1 Setting Up The Build Environment
OpenFIPS201 has been build tested on Windows 10 and 11, but there’s no reason to believe it won’t build on most major operating systems.
Make sure you have a suitable Java Development Kit (JDK) installed. For OpenFIPS201, the most appropriate version is Java SE 11 LTS, which can be downloaded from here:
Java Archive Downloads - Java SE 11 | Oracle AustraliaMake sure you set the environment variable
JAVA_HOME
to the full path to the SDK.
For example:JAVA_HOME=C:\Program Files\Java\jdk-11.0.13
To simplify the build process, the following third-party tools are already included in the repository under the tools directory:
Apache Ant (Apache Software Foundation, Apache Ant ) for the build processor
Ant-Javacard (Martin Paljak, GitHub - martinpaljak/ant-javacard ) for the Javacard build tasks
Javacard SDK 3.0.4 (Oracle, Java Archive Downloads) for the Target SDK
Javacard SDK 3.1.0 (Oracle, Java Card SDK Downloads) for the Build SDK
Next, you'll need to grab the latest OpenFIPS201 master branch:
git clone https://github.com/makinako/OpenFIPS201.git
Â
Drop to a command / terminal prompt and navigate to the
build
directory where you just cloned the repository.Run the
build.cmd
(Windows) orbuild.sh
(Linux) scriptYou are done!
The CAP file has now been created in thebin
directory and the Javadoc HTML has been generated in thedoc
directory.
It can be tempting to install the latest JDK, however all but the latest Java Card development kits (JC 3.1.0) are targeted to specific, older Java target versions that are not supported on newer JDK’s.
OpenFIPS201 targets JC 3.0.4 currently, which means it must be compiled to target 1.7.
Â
Â
Â
Â
OpenFIPS201 targets JC 3.0.4, but uses the latest 3.1.0 compiler. This is the recommended approach by Oracle.
Â
Â
Â
Â
3 Applet Architecture
OpenFIPS201 is built with the following high-level design goals in mind:
Simplicity and Readability - The code is designed to be a clean interpretation of the [SP 800-73] Part 2 document, using the standard terms wherever possible.
Flexibility - The file system, access control rules and applet behaviour are all configured from a single class before compilation, allowing for strict compliance to PIV or to allow for additional data objects or security requirements (PIV-I or CIV for example).
Production Quality - The project aims to be of a quality that can be used directly in a production environment and submitted for certification.
Low Memory Footprint - Although the file system itself is capable of taking up enormous amounts of EEPROM, the applet itself is designed to minimise its EEPROM and RAM footprint. Data Object arrays are only allocated when first written to and the APDU buffer is used where possible for intermediate operations.
Â
3.1 Component Hierarchy
Â
Â
Component | Description |
---|---|
OpenFIPS201 Facade | This is the derived implementation of the Javacard It implements the following functionality:
|
PIV | The implementation of all [SP800-73-4] commands and functionality. |
PIV Object | The base class from which all PIV dynamic objects derive. It contains the identification and access control information associated with all PIV objects. It defines the following attributes:
This class is abstract and cannot be instantiated. |
PIV Security Provider | This class is the entry point for all cryptographic operations. It performs the following:
|
Key Object | The base class from which all PIV dynamic Keys derive. It extends
|
PKI Key | The base class for asymmetric keys. It extends the
|
RSA Key | A concrete implementation of the |
ECC Key | A concrete implementation of the |
Symmetric Key | A concrete implementation of the |
Data Object | Represents a single PIV Data Object, which is accessed via the GET DATA and PUT DATA commands. |
TLV Reader | Implements ASN.1 BER and DER-TLV object validation and querying. |
TLV Writer | Implements ASN.1 BER and DER-TLV object validation and querying. |
Chain Buffer | Implements [ISO 7816] command chaining to a temporary command buffer so that other components need not consider the existence of chaining. |
CMVPIN | Extends the Java Card PIN interface to implement access to the GlobalPlatform Global PIN in a consistent manner. |
Â
3.1.1 Key Role
The following key roles are defined:
Role | Description |
---|---|
01 - ROLE_AUTHENTICATE | This key can be used for card/host authentication
|
02 - ROLE_SIGN | This key can be used for digital signature generation.
|
04 - ROLE_VERIFY | This key can be used for digital signature verification.
|
08 - ROLE_KEY_ESTABLISH | This key can be used for key establishment schemes.
|
10 - ROLE_SECURE_MESSAGING | This key can be used for secure messaging establishment.
|
3.1.2 Key Attributes
The following key attributes are defined:
Attribute | Description |
---|---|
01 - ATTR_ADMIN | This key can be used for administrative authentication |
02 - ATTR_GENERATE_ONLY | This key can only be generated on-card (i.e. injection is blocked). |
04 - ATTR_MUTUAL_ONLY | This key is limited to MUTUAL (host/card) authentication only. Setting this disables EXTERNAL and INTERNAL authentication for symmetric keys. |
Â
3.2 Applet Lifecycle
Â
OpenFIPS201 supports the following lifecycle states:
Â
State | Description |
---|---|
Installed | OpenFIPS201 is installed on the Card (in the appropriate GlobalPlatform Security Domain) and all memory has been allocated. The applet is inactive and an attempt to select it via its Application Identifier (AID) will fail. |
Selectable | OpenFIPS201 has been activated in the Card Manager and is now able to receive commands from a Terminal. By default the applet does not yet define any Configuration, Data Objects or Key values |
Personalised | The applet is now operational and able to perform cryptographic operations. |
Locked | The applet has been temporarily locked and is no longer selectable. This state can have a number of causes:
Once the applet is Locked, only the GlobalPlatform Security Domain is able to unlock it. |
Terminated | The applet has been irreversibly locked and can no longer be used. The following steps occur in order.
|
Â
3.3 Development Principles
OpenFIPS201 follows a number of design principles to ensure that undefined or unintended behaviour does not occur, whether through the fault of development (bugs), fault of use or malicious act.
Â
3.3.1 Private-Package Class Declarations
All classes in the OpenFIPS201 package shall be declared ‘Private-Package', with the intention that they are non-accessible outside the main package. This is intended to reduce attack surface related to static members.
// BAD
public class MyClass {
}
// GOOD
class MyClass {
}
3.3.2 Exception-based Error Handling
All functions generate errors via the Java Card exceptions paradigm, which causes the applet to stop functioning unless the exception is explicitly handled.
Return values are only ever informational or functional, they are never used to express the failure of a function to operate normally. Conversely, exceptions are never used to convey information or drive application flow.
This is done to prevent calling code from unintentionally ignoring error conditions, which may then lead to unintended behaviours or exposure to attackers.
3.3.3 Object Locking
Utility and Cryptographic objects make use of a simple Acquire and Release locking mechanism, which ensures that any unintended or malicious attempts to execute functionality are caught.
Before a call to any protected object is made, the caller must Acquire a lock. If a lock already exists, the object will throw an exception. Once a lock is requested, the caller must then explicitly release the object.
3.3.4 Early Initialisation - Critical Data
OpenFIPS201 ensures that all critical objects and buffers are defined at applet installation. This has a number of impacts:
It eliminates the chance of undefined behaviour due to allocation failures on memory-constrained devices.
The card issuance system is immediately aware of any memory allocation failures, which prevents installation and renders the applet unable to be selected.
It provides early visibility of how much memory the base installation of OpenFIPS201 uses
The following elements are instantiated at applet install:
All functional modules (classes)
The primary transient (RAM-based) temporary buffer (called the Scratch space)
The dedicated transient authentication state
The [ISO-7816] communications command-chain handler (Chain Buffer)
The PIV Implementation
The PIV Security Provider including all Java Card cryptographic primitive instances
TLV Parsing and Construction Utilities
3.3.5 Lazy Initialisation - Filesystem and Key Store
In contrast to critical data, OpenFIPS201 deliberately avoids allocating memory for dynamic objects until they are populated with data. This is because a PIV filesystem has the potential to consume large amounts of memory and data object lengths are not always known, so early instantiation would need to take into account worst-case memory usage which would further impact the applet footprint.
In any typical PIV deployment, many objects will remain unpopulated for the entire life-time of the applet. Lazy initialisation optimises this by only allocating memory for these resources until they are first used and the requested size is known.
This includes:
File System Descriptors
Data Objects
Key Objects
Â
3.3.6 Defined Cryptographic Boundary
All cryptographic operations occur inside specific classes and internal Java Card implementations are not accessible outside of these objects. This reduces the chances of sensitive cryptographic functions being used in an unintended or malicious way.
The classes that contain references to cryptographic primitive instances are:
PIV Security Provider
PIV Crypto
3.3.7 Optimised File Allocation Table
All Data Object and Key records are held by a simple linked list. Since it is possible that many data objects and keys will not be populated, OpenFIPS201 optimises this linked list by moving objects to the top of the list as they are allocated. This ensures that the lookup time is minimised as empty objects are never hit in normal operational circumstances.
3.3.8 Approved Algorithms
OpenFIPS201 makes use of only cryptographic mechanisms which are approved by:
Â
3.3.9 Critical Security Parameter (CSP) Management
All CSPs are carefully managed to ensure that the potential for exposure or misuse is limited. Some of the ways in which this is implemented are:
All cryptographic keys are only ever stored in Java Card
Key
objects, which are protected by the JCRE / JCVM.All PIN and PUK values are stored in Java Card
OwnerPin
objects, which are protected by the JCRE / JCVM.Keys and cryptographic primitives are kept within defined classes and access to them is only permitted through abstracted operations.
Transport of cryptographic keys is only ever permitted over a secure channel with command Encryption and MAC, never in plaintext.
Asymmetric Keys are able to be decorated with a 'Generate Only' attribute, which prevents key injection. This provides assurance of key ownership and guards against repudiation.
All temporary and intermediate values are zeroised immediately after they are no longer needed
Â
3.3.10 No ‘Roll Your Own’ Crypto
OpenFIPS201 does not make use of any cryptographic primitives that are defined in software, but rather makes use of the existing primitives provided by the Java Card API.
4 Environment - Java Card
OpenFIPS201 avoids the use of any platform-specific API outside of Java Card and GlobalPlatform namespaces, to ensure maximum compatibility with commercially available cards.
The minimum Java Card Runtime Environment (JCRE) version is targeted at v3.0.4 and as such, does not make use of functionality in later versions. There are several reasons for this:
A number of cryptographic primitives are not supported by JC22, especially in the Elliptic Curve domain. This makes it impossible to fully implement SP800-73-4 without resorting to a soft-crypto implementation.
The PIV requirement to format signature input blocks off-card, which is not supported by JC22 resulted in the need to implement a hack to encrypt using the private key. Moving to JC30 will allow the use of Signature with
signPreComputedHash()
andsetInitialDigest()
, which are both specifically intended for off-card signature block formatting.JC22 does not support the
Applet.reselectingApplet()
feature, which again is a breaking point for PIV. NIST have indicated they will permit certification exceptions to support JC22 cards, however this hasn't been tested to our knowledge.
4.1.1 Java Card API
The following Java Card API objects are required for OpenFIPS201 to install:
Class / Namespace | Requirement |
---|---|
javacard.framework.APDU | Mandatory |
javacard.framework.Applet | Mandatory |
javacard.framework.CardRuntimeException | Mandatory |
javacard.framework.ISO7816 | Mandatory |
javacard.framework.ISOException | Mandatory |
javacard.framework.JCSystem | Mandatory |
javacard.framework.OwnerPIN | Mandatory |
javacard.framework.PIN | Mandatory |
javacard.framework.PINException | Mandatory |
javacard.framework.Util | Mandatory |
javacard.security.AESKey | Optional |
javacard.security.CryptoException | Mandatory |
javacard.security.DESKey | Optional |
javacard.security.ECPrivateKey | Optional |
javacard.security.ECPublicKey | Optional |
javacard.security.KeyAgreement | Mandatory |
javacard.security.KeyBuilder | Mandatory |
javacard.security.KeyPair | Mandatory |
javacard.security.MessageDigest | Mandatory |
javacard.security.PrivateKey | Mandatory |
javacard.security.PublicKey | Mandatory |
javacard.security.RandomData | Mandatory |
javacard.security.RSAPrivateKey | Optional |
javacard.security.RSAPublicKey | Optional |
javacard.security.SecretKey | Mandatory |
javacard.security.Signature | Mandatory |
javacardx.crypto.Cipher | Mandatory |
Â
4.1.2 Cryptographic Primitives
OpenFIPS201 dynamically checks which cryptographic primitives are available on the target card during installation. If one or more are not available (cannot be instantiated), the applet will disable that mechanism and prevent keys of those types from being added to the file system during pre-personalisation.
The following primitives are used if available:
Class / Namespace |
---|
Cipher.ALG_AES_BLOCK_128_CBC_NOPAD |
Cipher.ALG_AES_BLOCK_128_ECB_NOPAD |
Cipher.ALG_DES_ECB_NOPAD |
Cipher.ALG_RSA_NOPAD |
KeyAgreement.ALG_EC_SVDP_DH_PLAIN |
MessageDigest.ALG_SHA_256 |
MessageDigest.ALG_SHA_384 |
Signature.ALG_ECDSA_SHA |
Signature.ALG_ECDSA_SHA_256 |
Signature.ALG_ECDSA_SHA_384 |
Signature.ALG_ECDSA_SHA_512 |
Signature.ALG_RSA_SHA_PKCS1 |
5 Environment - Global Platform
OpenFIPS201 makes use of functionality in the GlobalPlatform API for version 2.2.1 or higher
OpenFIPS201 avoids the use of any platform-specific API outside of Java Card and GlobalPlatform namespaces, to ensure maximum compatibility with commercially available cards.
OpenFIPS201 makes use of the Global Platform Secure Channel Protocol 03 functionality, specifically to mutually authenticate the card and the issuer (or card manager). For an administrative status to be considered valid, both the C-ENC and C-MAC protocol options must be set.
The following Global Platform API objects are required at a minimum:
Class / Namespace |
---|
org.globalplatform.GPSystem |
org.globalplatform.CVM |
org.globalplatform.SecureChannel |
Â
6 Applet Interoperability Testing
NIST has supplied testing documentation and software that is used to perform black-box testing of a PIV applet and/or middleware component.
OpenFIPS201 has been tested using this software, excluding tests that fall into a number of categories:
Unsupported features (Biometric On-Card Comparison)
Inapplicable (i.e. Middleware tests)
Data Format Validation (It tests the contents of a data object, which is outside the scope of the Card Application to enforce)
The document and software links can be found here:
PIV Card Application and Middleware Interface Test Guidelines (SP 800-73-4 Compliance)
 (Requires a password, which can be obtained from NIST with instructions provided on their web site)
6.1.1.1 Installation Requirements
PIV Test Runner requires the following:
Microsoft Windows XP or above
At least 40MB disk space
Oracle Java Runtime Environment (JRE) version 1.8 (Java 8) or later
"The Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6.0" (Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7 Download )
1 x contact (ISO-7816) PC/SC compliant reader
1 x contactless (ISO-14443) PC/SC compliant reader
2 x Javacard / GlobalPlatform smartcards
6.1.1.2 Installation and Configuration
Download and install the PIV Test Runner (from the above link) to a writable folder
Execute startTestRunner_SP800_73_4.bat in the install directory
Open the OPENFIPS201.xml configuration file
Customise the following configuration settings to your test readers
Configuration / Connectivity / Contact Reader Name
Configuration / Connectivity / Contactless Reader Name
6.1.1.3 Test Preparation
If you do not already have a compile OpenFIPS201 applet
Configure the OpenFIPS201 project (See Development)
Compile the OpenFIPS201 project
Load and install the OpenFIPS201 applet onto each target Javacard with the Default Applet privilege!
Perform pre-personalisation by executing the NIST Compliant Profile on each card
Execute the Test Personalisation on each card
6.1.1.4 Test Execution
Unless you are testing a comprehensive PIV setup (i.e. Middleware and Personalisation system), it is not recommended to use the 'Run All' functionality. Instead, only selected tests should be executed from the list below.
ChangeReferenceDataCommand
GeneralAuthenticateCommand
GenerateAsymmetricKeyPairCommand
GetDataCommand
PutDataCommand
ResetRetryCounterCommand
ChangeReferenceDataCommand
SelectCommand
VerifyCommand
These can be executed either individually, or all selected. PIV Test Runner does not appear to provide a mechanism to generate a 'test profile' file.
6.1.1.5 Test Results
PIV Test Runner provides summary test results by clicking on the parent Test item. Each test category will show either PASS, FAIL or blank if they were not executed.
Inside each test sub-category you have the option to select the Log tab, which will give detailed diagnostic output for the execution of each test with a summary of each step outcome at the end of the log.
Note that all test numbering maps back to the NIST test documentation described at the start of this page.