Skip to end of banner
Go to start of banner

Applet Development

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 6 Next »

This section describes the development environment and architecture of the OpenFIPS201 applet.

1 Contents

2 Overview

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 Building OpenFIPS201

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.

  1. 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:
    https://www.oracle.com/au/java/technologies/javase/jdk11-archive-downloads.html

  2. Make 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.

  3. To simplify the build process, the following third-party tools are already included in the repository under the tools directory:

    1. Apache Ant (Apache Software Foundation, https://ant.apache.org/ )

    2. ant-javacard (Martin Paljak, https://github.com/martinpaljak/ant-javacard )

    3. Javacard SDK 3.0.4 (Oracle, https://www.oracle.com/java/technologies/java-archive-downloads-javame-downloads.html#javacardkitv304) for the Target SDK

    4. Javacard SDK 3.1.0 (Oracle, https://www.oracle.com/java/technologies/javacard-sdk-downloads.html) for the Build SDK

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.

First, you'll need to grab the latest OpenFIPS201 master branch:

git clone https://github.com/makinako/OpenFIPS201.git

To simplify the build process, the following third-party tools are already included in the repository under the tools directory:

In addition, the Oracle Java SE JDK and JRE must be installed (JDK v9 is not recommended). (http://www.oracle.com/technetwork/java/javase/downloads/index.html )

3.1 Build Process

From the root repository folder:

  1. Go to the build folder

  2. Edit the build.cmd and set the 'JDK' environment variable to the version you have installed.

  3. Optionally, edit the build.xml ant configuration file, overriding any default build properties at the top (this is where you can change the target Javacard or GlobalPlatform version in particular).

  4. Run build.cmd, which will build the CAP file to the ./bin folder and the intrinsic documentation to the ./doc folder.

3.2 Applet Configuration

The OpenFIPS201 source contains a file Config.java, which drives the advanced behaviour of the applet. Each feature / parameter is described below, along with the requirement for compliance with NIST SP800-73-4.

3.2.1.1 Features

Feature

Description

Default Value

PIV TEST VECTORS

This must only be enabled for protocol debugging and analysis, as this forces the applet to use FIXED values for cryptographic nonces and will cripple security.
SP800-73-4 Requirement: Must be set to false

This may be removed in the accredited release to comply with ISO 19790. This will likely be replaced with a separate identical build with test vectors included.

False

RESTRICT SCP TO CONTACT

If set to true, an authentication to GlobalPlatform will fail on the contactless interface.
SP800-73-4 Requirement: Issuer-defined

True

ERROR ON EMPTY DATA OBJECT

If set to true, a call to GET DATA for an object that exists in the file system, but which has not been initialised with data will result in SW_FILE_NOT_FOUND. If set to false, it will return an empty data field with SW OK.
SP800-73-4 Requirement: Issuer-defined

False

DISCOVERY OBJECT DEFAULT

If set to true, when the discovery object is created it will automatically be populated with a default value based on the configured parameters (specifically the PIN policy element dynamic elements).
SP800-73-4 Requirement: Issuer-defined

True

PIN CARD ENABLED

Indicates that the mandatory PIV Card Application PIN satisfies the PIV Access Control Rules (ACRs) for command execution and data object access.
SP800-73-4 Requirement: Issuer-defined

False

PIN GLOBAL ENABLED

Indicates that the optional 'Global PIN' feature of PIV is enabled.
SP800-73-4 Requirement: Issuer-defined

False

PIN GLOBAL PREFERRED

Indicates that the Global PIN is the primary PIN used to satisfy the PIV ACRs for command execution and object access.
SP800-73-4 Requirement: Issuer-defined

False

PIN GLOBAL CHANGE

Indicates that the Global PIN may be updated by the PIV applet.
SP800-73-4 Requirement: Issuer-defined

False

PIN INIT RANDOM

Indicates that the PIN will be set to a random value at applet instantiation. If this is set to False, it will be set to a default value defined in the same Config file (DEFAULT PIN).
SP800-73-4 Requirement: Issuer-defined

True

PUK CHANGE

Indicates that the PUK may be updated by the PIV applet.
SP800-73-4 Requirement: Issuer-defined

True

PUK INIT RANDOM

Indicates that the PUK will be set to a random value at applet instantiation. If this is set to False, it will be set to a default value defined in the same Config file (DEFAULT PUK).
SP800-73-4 Requirement: Issuer-defined

True

PIN OVER CONTACTLESS

Permits the PIN or Global PIN to be used over contactless without the need for the VCI condition.
SP800-73-4 Requirement: Must be set to false

False

PUK OVER CONTACTLESS

Permits the PUK to be used over contactless without the need for the VCI condition.
SP800-73-4 Requirement: Must be set to false

False

3.2.1.2 PIN and PUK Settings

Parameter

Description

Default Value

PIN RETRIES

The number of retries before the PIN object is blocked.
SP800-73-4 Requirement: Issuer-defined

6

PIN RETRIES INTERMEDIATE

The number of retries remaining before the PIN object is blocked on the contactless interface only.
SP800-73-4 Requirement: Issuer-defined

1

PUK RETRIES

The number of retries before the PUK object is blocked.
SP800-73-4 Requirement: Issuer-defined

6

PUK RETRIES INTERMEDIATE

The number of retries before the PIN object is blocked on the contactless interface only.
SP800-73-4 Requirement: Issuer-defined

1

PIN LENGTH MIN

The minimum length of the PIN value (SP800-73-4 default is '6' - NOTE: Changing this value from its default will break PIV compliance).
SP800-73-4 Requirement: Must be set to 6

6

PIN LENGTH MAX

The maximum length of the PIN value (SP800-73-4 default is '8' - NOTE: Changing this value from its default will break PIV compliance).
SP800-73-4 Requirement: Must be set to 8

8

4 Applet Architecture

Component

Description

OpenFIPS201 Facade

This is the derived implementation of the Javacard Applet class and provides the entry point for all communications to the applet.

It implements the following functionality:

  • Applet installation and memory allocation

  • Applet selection and deselection

  • APDU processing

  • GP Secure Channel processing

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:

  • Object Identifier

  • Access Mode - Contact Interface

  • Access Mode - Contactless Interface

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:

  1. Manages the cryptographic key store.

  2. Permits querying of available keys.

  3. Maintains card verification data and state.

  4. Permits querying of PIV Object access conditions against the current verification and authentication state.

Key Object

The base class from which all PIV dynamic Keys derive. It extends PIV Object to include additional attributes.

  • Cryptographic Mechanism

  • Key Role

  • Key Attributes

This class is abstract and cannot be instantiated.

PKI Key

The base class for asymmetric keys. It extends the Key Object to include additional functionality:

  • Signing operation

  • Key Agreement operation

  • Key Generation operation

This class is abstract and cannot be instantiated.

RSA Key

A concrete implementation of the PKI Key class, which provides RSA cryptographic operations.

This class implements the Lockable pattern.

ECC Key

A concrete implementation of the PKI Key class, which provides Elliptic Curve cryptographic operations.

This class implements the Lockable pattern.

Symmetric Key

A concrete implementation of the Key Object class, which provides AES and TripleDES cryptographic operations.

This class implements the Lockable pattern.

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.

This class is implemented as a Singleton and implements the Lockable pattern.

TLV Writer

Implements ASN.1 BER and DER-TLV object validation and querying.

This class is implemented as a Singleton and implements the Lockable pattern.

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.

4.1.1 Key Role

The following key roles are defined:

Role

Description

01 - ROLE_AUTHENTICATE

This key can be used for card/host authentication

  • Symmetric Keys - Permit Internal, External and Mutual Authentication.

  • RSA - Not supported (RSA authentication is just a Digital Signature of a challenge)

  • ECC - Not supported (ECC authentication is just a Digital Signature of a challenge)

02 - ROLE_SIGN

This key can be used for digital signature generation.

  • Symmetric Keys - Not supported (Could be used for MAC generation)

  • RSA - RSA Digital Signature

  • ECC - ECDSA

04 - ROLE_VERIFY

This key can be used for digital signature verification.

  • Symmetric Keys - Not supported (Could be used for MAC verification)

  • RSA - RSA Digital Signature

  • ECC - Elliptic Curve Digital Signature Algorithm (ECDSA)

Currently there is no PIV case for this, but reserve it in case we want the extension.

08 - ROLE_KEY_ESTABLISH

This key can be used for key establishment schemes.

  • Symmetric Keys - Not supported

  • RSA - RSA Key Transport

  • ECC - Elliptic Curve Diffie Hellman (ECDH)

10 - ROLE_SECURE_MESSAGING

This key can be used for secure messaging establishment.

  • Symmetric Keys - Not supported

  • RSA - Not supported

  • ECC - Opacity ZKM

The Key Role parameter is a control bitmap, meaning multiple values can be combined.

4.1.2 Key Attributes

The following key attributes are defined:

Attribute

Description

01 - ATTR_ADMIN

This key can be used for administrative authentication

This attribute is only applicable to symmetric keys.

02 - ATTR_GENERATE_ONLY

This key can only be generated on-card (i.e. injection is blocked).

This attribute is only applicable to asymmetric keys (RSA and ECC).

04 - ATTR_MUTUAL_ONLY

This key is limited to MUTUAL (host/card) authentication only. Setting this disables EXTERNAL and INTERNAL authentication for symmetric keys.

This attribute is only applicable to symmetric keys.

The Key Attribute parameter is a control bitmap, meaning multiple values can be combined.

4.1 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

This is the only state in which Pre-Personalisation commands are available.

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:

  • The Card Manager has determined that the applet should be locked

  • OpenFIPS201 has determined that the applet should be locked

  • An authorised Card Administrator has requested the applet be locked explicitly

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.

  1. The applet internally sets a flag to indicate that it is now in the Terminated state.

  2. All authentication and verification states are reset

  3. All key values are cleared

  4. All verification values are cleared

  5. All data objects are cleared

  6. Garbage collection is requested from the card manager, if available.

  7. The applet is locked by the card manager and is no longer selectable.

If power is removed from the card prior to completion of the above steps, they will be continued upon next selection. This is to ensure that all Keys, Data Objects and Verification values are removed.

4.2 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.

It is extremely important that the underlying Hardware, OS and Javacard runtime environment is considered in terms of the overall assurance level required, since OpenFIPS201 relies on these for all cryptographic functions and secure storage of critical security parameters.

4.2.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 {
}

4.2.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.

4.2.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.

4.2.4 Early Initialisation - Critical Data

OpenFIPS201 ensures that all critical objects and buffers are defined at applet installation. This has a number of impacts:

  1. It eliminates the chance of undefined behaviour due to allocation failures on memory-constrained devices.

  2. The card issuance system is immediately aware of any memory allocation failures, which prevents installation and renders the applet unable to be selected.

  3. 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

4.2.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

For Data Objects:

  • Memory is allocated on first-write. If memory allocation fails, the object remains uninitialised and unchanged.

  • Subsequent writes cause the initial object to be de-allocated and then a new object is allocated. This causes the Garbage Collection process to be requested if available.

For Key Objects:

  • For Key Objects, allocation occurs either when the first key element is injected or when key generation is requested. In both cases, all memory relating to the Key object is allocated to prevent the possibility of partial allocation causing undefined behaviour.

  • For Key Objects, memory is de-allocated when the key is explicitly cleared via caller request.

4.2.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

4.2.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.

4.2.8 Approved Algorithms

OpenFIPS201 makes use of only cryptographic mechanisms which are approved by:

4.2.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

4.2.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.

In order to continue to support Java Card 3.0.4, OpenFIPS201 has implemented Signature.ALG_AES_CMAC_128 for Secure Messaging and although it makes use of the underlying AES primitive, this is technically a violation of this principle. If the card OS supports this algorithm, then the card implementation shall be used, otherwise the in-package implementation is used.

5 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() and setInitialDigest(), 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.

5.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

5.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

If any of the following primitives are not supported, this will implicitly disable Secure Messaging functionality.

  • KeyAgreement.ALG_EC_SVDP_DH_PLAIN

  • MessageDigest.ALG_SHA_256

  • MessageDigest.ALG_SHA_384

  • Cipher.ALG_AES_BLOCK_128_CBC_NOPAD

6 Environment - Global Platform

  • OpenFIPS201 makes use of functionality in the GlobalPlatform API for version 2.1.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

7 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:

7.1.1.1 Installation Requirements

PIV Test Runner requires the following:

7.1.1.2 Installation and Configuration

  1. Download and install the PIV Test Runner (from the above link) to a writable folder

  2. Execute startTestRunner_SP800_73_4.bat in the install directory

  3. Open the OPENFIPS201.xml configuration file

  4. Customise the following configuration settings to your test readers

    • Configuration / Connectivity / Contact Reader Name

    • Configuration / Connectivity / Contactless Reader Name

7.1.1.3 Test Preparation

  1. If you do not already have a compile OpenFIPS201 applet

    • Configure the OpenFIPS201 project (See Development)

    • Compile the OpenFIPS201 project

  2. Load and install the OpenFIPS201 applet onto each target Javacard with the Default Applet privilege!

  3. Perform pre-personalisation by executing the NIST Compliant Profile on each card

  4. Execute the Test Personalisation on each card

7.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.

7.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.

  • No labels