diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a09852..5ea783f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Documentation of recommended status words for ApduInterpreterSpi implementations +- Exception handling guidelines for CommandProcessorApi implementations +- Added `KeyStorageType` enum to specify memory type (VOLATILE or NON_VOLATILE). +- Added `loadKey` method to `CommandProcessorApi` interface using `KeyStorageType` for loading card-specific + authentication keys into reader memory. +- Added `generalAuthenticate` method to `CommandProcessorApi` interface for performing authentication to contactless + cards using previously loaded keys. +### Changed +- Enhanced JavaDoc with comprehensive error handling information +- Added status word reference table following ISO 7816-4 and PC/SC standards ## [1.0.0] - 2025-07-08 This is the initial release. diff --git a/gradle.properties b/gradle.properties index d51898b..4a99b9c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group = org.eclipse.keyple title = Keyple Plugin Storage Card API description = API dedicated to standardize communication between Keyple plugins and APDU interpreters for storage card processing -version = 1.0.1-SNAPSHOT +version = 1.1.0-SNAPSHOT # Java Configuration javaSourceLevel = 1.8 diff --git a/src/main/java/org/eclipse/keyple/core/plugin/storagecard/PluginStorageCardApiProperties.java b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/PluginStorageCardApiProperties.java index 00e76ad..35a481f 100644 --- a/src/main/java/org/eclipse/keyple/core/plugin/storagecard/PluginStorageCardApiProperties.java +++ b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/PluginStorageCardApiProperties.java @@ -22,7 +22,7 @@ public final class PluginStorageCardApiProperties { * * @since 1.0.0 */ - public static final String VERSION = "1.0"; + public static final String VERSION = "1.1"; /** Private constructor */ private PluginStorageCardApiProperties() {} diff --git a/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/CommandProcessorApi.java b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/CommandProcessorApi.java index 200fe5a..1c1f97b 100644 --- a/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/CommandProcessorApi.java +++ b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/CommandProcessorApi.java @@ -16,6 +16,20 @@ * *
To be implemented by the plugin. * + *
All methods may throw exceptions to indicate error conditions. Implementations should + * distinguish between: + * + *
The exception message should provide clear diagnostic information about the failure cause. + * * @since 1.0.0 */ public interface CommandProcessorApi { @@ -84,4 +98,90 @@ public interface CommandProcessorApi { * @since 1.0.0 */ void writeBlock(int blockAddress, byte[] data) throws Exception; + + /** + * Loads a card-specific authentication key into the reader's memory. + * + *
This method stores a card key in either volatile (RAM) or non-volatile (EEPROM) memory of + * the card reader. The key can be subsequently used by the {@link #generalAuthenticate(int, int, + * int)} method to authenticate to the card. This command can be used for all kinds of contactless + * cards. + * + *
Volatile memory provides temporary storage that is cleared when the reader loses power, + * while non-volatile memory persists across power cycles. The availability of non-volatile memory + * depends on the specific reader hardware. + * + *
The key structure and length depend on the card type. For example: + * + *
The key number parameter identifies the storage location in the reader's memory. The valid + * range and meaning of key numbers depend on the reader implementation and whether volatile or + * non-volatile memory is used. Consult the reader documentation for specific key number + * assignments. + * + *
Note that keys stored in memory cannot be read back for security reasons. Once loaded, they + * can only be used for authentication operations. + * + * @param keyStorageType The type of memory to store the key in (VOLATILE or NON_VOLATILE). + * @param keyNumber The key index identifying the storage location. Valid ranges depend on the + * reader implementation and memory type. + * @param key A byte array containing the card-specific key value. Must not be null. The required + * length depends on the card type and authentication algorithm. + * @throws IllegalArgumentException if {@code keyStorageType} or {@code key} is null, if the key + * length is not valid for the card type, or if {@code keyNumber} is not in the valid range + * for the reader and memory type. + * @throws Exception if the load operation fails, if the specified memory type is not available on + * the reader hardware, or if a communication error occurs. + * @see #generalAuthenticate(int, int, int) + * @since 1.1.0 + */ + void loadKey(KeyStorageType keyStorageType, int keyNumber, byte[] key) + throws Exception; // NOSONAR + + /** + * Performs authentication to a contactless card using a previously loaded key. + * + *
This method authenticates to a specific memory location on the card using a key that was + * previously loaded into the reader's memory via the {@link #loadKey(KeyStorageType, int, + * byte[])} method. Successful authentication is typically required before performing read or + * write operations on protected memory areas. + * + *
The authentication process establishes a secure session between the reader and the card. The + * block address represents the block number or starting byte number of the card to be + * authenticated, depending on the card type. + * + *
The key type parameter is card-specific and indicates which type of key to use for + * authentication. Examples: + * + *
The key number parameter references a key previously loaded via {@link + * #loadKey(KeyStorageType, int, byte[])} and identifies which stored key to use for this + * authentication operation. + * + * @param blockAddress The block number or starting byte number on the card where authentication + * is to be performed. Valid range depends on the card type and memory structure. + * @param keyType The type of key to use for authentication. The valid values are card-specific + * (e.g., 0x60 or 0x61 for Mifare cards). + * @param keyNumber The index of the previously loaded key to use for authentication. Must + * reference a key that was loaded via {@link #loadKey(KeyStorageType, int, byte[])}. + * @return {@code true} if authentication succeeded, {@code false} if authentication failed (e.g., + * incorrect key). + * @throws IllegalArgumentException if {@code blockAddress} is out of valid range for the card + * type, if {@code keyType} is not supported by the card, or if {@code keyNumber} does not + * reference a valid loaded key. + * @throws Exception if the referenced key was not previously loaded, if the card does not support + * authentication, or if a communication error occurs. + * @see #loadKey(KeyStorageType, int, byte[]) + * @since 1.1.0 + */ + boolean generalAuthenticate(int blockAddress, int keyType, int keyNumber) + throws Exception; // NOSONAR } diff --git a/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/KeyStorageType.java b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/KeyStorageType.java new file mode 100644 index 0000000..f3884bd --- /dev/null +++ b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/KeyStorageType.java @@ -0,0 +1,39 @@ +/* ************************************************************************************** + * Copyright (c) 2026 Calypso Networks Association https://calypsonet.org/ + * + * See the NOTICE file(s) distributed with this work for additional information + * regarding copyright ownership. + * + * This program and the accompanying materials are made available under the terms of the + * MIT License which is available at https://opensource.org/licenses/MIT + * + * SPDX-License-Identifier: MIT + ************************************************************************************** */ +package org.eclipse.keyple.core.plugin.storagecard.internal; + +/** + * Enumeration defining the memory types available for key storage in the reader. + * + * @since 1.1.0 + */ +public enum KeyStorageType { + /** + * Volatile memory (RAM). + * + *
Keys stored here are lost when the reader is powered off or reset. This is generally faster + * and supports unlimited write cycles. + * + * @since 1.1.0 + */ + VOLATILE, + + /** + * Non-volatile memory (EEPROM/Flash). + * + *
Keys stored here persist across power cycles. Note that non-volatile memory typically has a + * limited number of write cycles. + * + * @since 1.1.0 + */ + NON_VOLATILE +} diff --git a/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/spi/ApduInterpreterFactorySpi.java b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/spi/ApduInterpreterFactorySpi.java index b7ef840..cf49eae 100644 --- a/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/spi/ApduInterpreterFactorySpi.java +++ b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/spi/ApduInterpreterFactorySpi.java @@ -20,6 +20,7 @@ * * @since 1.0.0 */ +@FunctionalInterface public interface ApduInterpreterFactorySpi extends ApduInterpreterFactory { /** diff --git a/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/spi/ApduInterpreterSpi.java b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/spi/ApduInterpreterSpi.java index 4d627e4..0182968 100644 --- a/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/spi/ApduInterpreterSpi.java +++ b/src/main/java/org/eclipse/keyple/core/plugin/storagecard/internal/spi/ApduInterpreterSpi.java @@ -12,20 +12,96 @@ package org.eclipse.keyple.core.plugin.storagecard.internal.spi; import org.eclipse.keyple.core.plugin.storagecard.internal.CommandProcessorApi; +import org.eclipse.keyple.core.plugin.storagecard.internal.KeyStorageType; /** - * Interface defining an APDU interpreter for processing commands sent to a card. + * Interface defining an APDU interpreter for processing commands sent to storage cards. * *
Its implementation is provided by {@link ApduInterpreterFactorySpi}. * *
Upon calling {@code processApdu}, implementations determine how to invoke the appropriate - * methods of {@link CommandProcessorApi} based on the card type. + * methods of {@link CommandProcessorApi} based on the APDU class byte (CLA) and instruction (INS). * - *
For standard ISO 7816-4 APDUs, the interpreter directly calls {@link - * CommandProcessorApi#transmitIsoApdu(byte[])}. For storage-type cards, the interpreter translates - * the APDU into specific read/write operations using {@link CommandProcessorApi#getUID()}, {@link - * CommandProcessorApi#readBlock(int, int)} and {@link CommandProcessorApi#writeBlock(int, byte[])}. + *
The interpreter follows a two-pathway processing model: + * + *
INS 0xCA → {@link CommandProcessorApi#getUID()} - Get card UID
+ * INS 0xB0 → {@link CommandProcessorApi#readBlock(int, int)} - Read binary
+ * data
+ * INS 0xD6 → {@link CommandProcessorApi#writeBlock(int, byte[])} - Write
+ * binary data
+ * INS 0x82 → {@link CommandProcessorApi#loadKey(KeyStorageType, int,
+ * byte[])} - Load authentication key
+ * INS 0x86 → {@link CommandProcessorApi#generalAuthenticate(int, int,
+ * int)} - Authenticate with key
+ * This interface follows a trust-based validation approach: + * + *
Implementations return ISO 7816-4 / PC/SC compliant status words for the following conditions: + * + *
| Status Word | Code | Usage |
|---|---|---|
| Success | 0x9000 | Successful execution |
| Security status not satisfied | 0x6982 | Authentication failed (PC/SC + * compliant) |
| INS not supported | 0x6D00 | Unknown instruction code |
The following error conditions may result in exceptions: + * + *
Note: Parameter validation (P1/P2 values, data lengths, key numbers, etc.) is + * the responsibility of the card extension generating the APDUs, not this interface or its + * implementations. + * + *
Storage card commands (CLA=0xFF) follow the PC/SC v2.01.09 specification: + * + *
FF 82 [P1] [P2] 06 [6-byte key]
+ * FF 86 00 00 05 [version][addr-MSB][addr-LSB][key-type][key-num]
+ *
+ * FF CA 00 00 [Le]
+ * FF B0 [P1] [P2] [Le]
+ * FF D6 [P1] [P2] [Lc] [data]
+ *