A Java command-line application that simulates a FIDO2 authenticator for registration (create
) and authentication (get
) flows, with enhanced debugging and interoperability features. Designed with modern architectural patterns and SOLID principles.
Author: Jordi Murgo (jordi.murgo@gmail.com)
- Quick Start
- Features
- CLI Reference
- Usage Examples
- Advanced Usage
- Configuration
- Architecture
- WebAuthn.io Integration Scripts
- Troubleshooting
- Contributing
- Changelog
- License
- Java 11 or newer
- Maven
# Build the project
mvn clean package
# Display information about the current credentials
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar info --pretty
# Create a sample credential (using example file)
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar create --input create_options.json --pretty
- Simulates
navigator.credentials.create()
andnavigator.credentials.get()
- Input: JSON for
PublicKeyCredentialCreationOptions
(create) orPublicKeyCredentialRequestOptions
(get) - Output: JSON representing the FIDO2
PublicKeyCredential
response
- SOLID architecture with clean separation of concerns
- Modern functional programming with Optional, Stream API and lambdas
- Robust validation with defensive approach and elegant exception handling
- Structured logging with appropriate levels
- Enhanced metadata storage in JSON format with rich credential information
- PEM-encoded public key storage for improved interoperability
- Detailed attestation and authenticator data decoding for debugging
- Save output directly to file with
--output
option - Pretty-print JSON output with
--pretty
option - Detailed logging with
--verbose
option - Clean JSON-only output with
--json-only
option for scripting
- Key storage: Java KeyStore (PKCS12) for secure credential operations
- Cryptography: BouncyCastle and Yubico's WebAuthn libraries
- JSON Processing: Jackson with CBOR support and custom deserializers
- Codificación: Soporte para Base64, Base64URL y formatos binarios
- CLI: Picocli for command-line processing
- Logging: SLF4J con implementación Logback
Option | Short | Description |
---|---|---|
--input <FILE> |
-i |
Specify an input file containing JSON options |
--output <FILE> |
-o |
Save the output to a specified file |
--pretty |
Format the JSON output with indentation for better readability | |
--verbose |
Enable detailed logging and show extended information | |
--json-only |
Output only the JSON response (useful for scripting) | |
--interactive |
Enable interactive credential selection (for get operation) |
|
--format <FORMAT> |
-f |
Output format (default, bytes, ints, ping) |
--help |
-h |
Show help message |
--version |
-V |
Print version information and exit |
Operation | Description |
---|---|
create |
Simulates credential creation (registration) |
get |
Simulates credential usage (authentication) |
info |
Displays information about stored credentials |
You can provide input to the CLI in three ways:
-
Input file (recommended for large/complex JSON):
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar <create|get> --input <input.json>
-
Direct JSON string argument:
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar <create|get> '{JSON data...}'
-
Standard input (pipe or keyboard):
cat input.json | java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar <create|get>
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar create -i create_options.json -o response.json
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar create -i create_options.json -f bytes --pretty
{
"challenge": "TEmqTQU6DhV2SaO0YFTM15KsqWyiFqpjHWa43HT7wBkKLNVQQttG5ADyRXjR8GZNFl8kexjNUKYwl6JF2MxHDA",
"rp": {
"name": "Example RP",
"id": "example.com"
},
"user": {
"id": "user123",
"name": "user@example.com",
"displayName": "Example User"
},
"pubKeyCredParams": [
{"type": "public-key", "alg": -7},
{"type": "public-key", "alg": -257}
],
"timeout": 60000,
"attestation": "direct",
"authenticatorSelection": {
"authenticatorAttachment": "platform",
"requireResidentKey": false,
"residentKey": "preferred",
"userVerification": "preferred"
}
}
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar get --input get_options.json
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar info --pretty
Los niveles de log se pueden configurar en logback.xml
. Los niveles disponibles son:
TRACE
: Muestra toda la información, incluyendo el procesamiento detallado de desafíosDEBUG
: Información detallada de depuraciónINFO
: Información general del flujo de la aplicaciónWARN
: Advertencias de posibles problemasERROR
: Errores que requieren atención
TRACE - Deserializando campo 'challenge' desde string base64url (88 caracteres)
DEBUG - Challenge bytes (hex): 4c49efbfbd4d053a0e157649...
DEBUG - Challenge base64url: TEnvv71NBToOFXZJ77-977-9YFTvv73Xku...
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar create --input create_options.json --pretty
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar create --input create_options.json --output response.json
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar create --input create_options.json --json-only
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar info --verbose --pretty
You can provide the input JSON as Base64-encoded content:
base64 -i create_options.json | java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar create
When using get
with multiple available credentials:
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar get --input get_options.json --interactive
During credential creation, the attestation object is automatically decoded and displayed.
The simulator supports different output formats for binary data in the response. You can specify the format using the --format
or -f
option:
java -jar target/fido2-client-simulator-1.1-SNAPSHOT.jar create -i create_options.json -f bytes
Format | Description |
---|---|
default |
Uses base64url for all binary fields |
bytes |
Outputs binary data as arrays of signed bytes (-128 to 127) |
ints |
Outputs binary data as arrays of unsigned integers (0-255) |
ping |
Optimized format for Ping Identity compatibility |
Formats are defined in src/main/resources/configuration.yaml
. Each format specifies how different fields should be encoded:
base64
: Standard Base64 encoding (with +/=)base64url
: URL-safe Base64 encoding (with -_)byteArray
: Array of signed bytes (-128 to 127)intArray
: Array of unsigned integers (0-255)string
: Try to decode as UTF-8 text (falls back to base64url if not valid)number
: mantains the number as it isobject
: mantains the object as it isnull
: Sets the field to null (type'null'
in the configuration)remove
: Exclude the field from output
The simulator uses a YAML configuration file for format definitions and other settings. The default configuration is loaded from the classpath at configuration.yaml
.
The configuration is loaded from the following locations in order of precedence:
- File specified by
FIDO2_CONFIG
environment variable config/configuration.yaml
in the current directoryconfiguration.yaml
in the current directory- Default configuration from classpath
# Keystore settings
keystore:
path: fido2_keystore.p12
password: changeme
metadataPath: fido2_keystore_metadata.json
# Logging level (DEBUG, INFO, WARN, ERROR)
logLevel: INFO
# Output formats configuration
formats:
# Default format - uses base64url for binary fields (WebAuthn standard)
default:
id: base64url
rawId: base64url
authenticatorData: base64url
clientDataJSON: base64url
signature: base64url
userHandle: base64url
attestationObject: base64url
publicKey: base64url
# Bytes format - outputs binary data as signed byte arrays
bytes:
id: base64url
rawId: byteArray
authenticatorData: byteArray
clientDataJSON: string
signature: byteArray
userHandle: base64url
attestationObject: byteArray
publicKey: byteArray
# Ints format - outputs binary data as unsigned integers
ints:
id: base64url
rawId: intArray
authenticatorData: intArray
clientDataJSON: string
signature: intArray
userHandle: base64url
attestationObject: intArray
publicKey: intArray
# Ping format - optimized for Ping Identity compatibility
ping:
id: 'null'
rawId: 'base64url'
clientDataJSON: 'string'
attestationObject: 'byteArray'
authenticatorData: 'byteArray'
publicKey: 'null'
publicKeyAlgorithm: 'null'
signature: 'byteArray'
userHandle: 'null'
fido2_keystore.p12
: Stores credential private keys in PKCS12 formatfido2_keystore_metadata.json
: Stores credential metadata including:- Registration response JSON
- RP (Relying Party) information
- User information
- Public key details
- Creation timestamp
- Credential ID and other metadata
graph TD
CLI[CLI - Command Line Interface] --> App[Fido2ClientApp]
App --> Factory[HandlerFactory]
Factory --> CreateH[CreateHandler]
Factory --> GetH[GetHandler]
Factory --> InfoH[InfoHandler]
CreateH --> CredStore[CredentialStore]
GetH --> CredStore
InfoH --> CredStore
CredStore --> KeyStore[KeyStoreManager]
KeyStore --> PKCS12[(PKCS12 KeyStore)]
KeyStore --> MetaData[(JSON Metadata)]
classDef interface fill:#f9f,stroke:#333,stroke-dasharray: 5 5;
classDef implementation fill:#9cf,stroke:#333;
classDef data fill:#fcf,stroke:#333;
class CredStore interface;
class KeyStore,CreateH,GetH,InfoH,Factory implementation;
class PKCS12,MetaData data;
class CreateH,GetH,InfoH implements_CommandHandler;
%% Note: All handlers now implement CommandHandler interface
%% InfoHandler is now shown in the diagram as well.
CredentialStore
acts as an abstract repository for credential storage operations, decoupling business logic from the persistence mechanism.
Implementation of the Factory pattern for creating specific handlers.
The CreateHandler
, GetHandler
, and InfoHandler
handlers implement different strategies for processing FIDO2 operations, sharing the common CommandHandler
interface.
Use of modern functional programming techniques for more concise and safer code.
- Testability: The use of interfaces facilitates testing with mocks.
- Extensibility: New storage types can implement
CredentialStore
. - Maintainability: Clear separation of responsibilities.
- Security: Robust exception handling and input validation.
- Evolution: Facilitates the incorporation of new features without modifying existing code.
The project includes two example scripts that demonstrate how to use FIDO2 Client Simulator with the WebAuthn.io demo site.
sequenceDiagram
participant Simulator as fido2-client-simulator.jar
participant Script as webauthn-io-tutorial-registration.sh
participant Curl as curl
participant WebAuthn as https://webauthn.io
activate Script
Note over Script: Start
Script->>Curl: Request registration options
Curl->>WebAuthn: POST /registration/options
WebAuthn-->>Curl: Return PublicKeyCredentialCreationOptions
Curl-->>Script: Save options to file
Script->>Simulator: Pass options to simulator
Note right of Simulator: Generate key pair & attestation
Simulator-->>Script: Return credential response
Script->>Curl: Submit credential for verification
Curl->>WebAuthn: POST /registration/verification
WebAuthn-->>Curl: Verify and return result
Curl-->>Script: Report verification status
Note over Script: Save all data for analysis
sequenceDiagram
participant Simulator as fido2-client-simulator.jar
participant Script as webauthn-io-tutorial-authentication.sh
participant Curl as curl
participant WebAuthn as https://webauthn.io
activate Script
Note over Script: Start
Script->>Curl: Request authentication options
Curl->>WebAuthn: POST /authentication/options
WebAuthn-->>Curl: Return PublicKeyCredentialRequestOptions
Curl-->>Script: Save options to file
Script->>Simulator: Pass options to simulator
Note right of Simulator: Load credential & generate assertion
Simulator-->>Script: Return assertion response
Script->>Curl: Submit assertion for verification
Curl->>WebAuthn: POST /authentication/verification
WebAuthn-->>Curl: Verify and return result
Curl-->>Script: Report verification status
Note over Script: Save all data for analysis
El simulador maneja automáticamente los desafíos durante el registro y autenticación. Si encuentras problemas:
-
Formato del Challenge:
- Asegúrate de que el challenge esté en formato Base64URL
- El simulador intentará decodificar automáticamente si está en otro formato
-
Verificación del Challenge:
- Durante el registro, se valida que el challenge no se modifique
- Se incluyen logs detallados con el prefijo
ByteArrayDeserializer
para depuración
-
Logs de Depuración:
- Usa
--verbose
para ver información detallada del procesamiento - Los desafíos se registran en formato hexadecimal para facilitar la comparación
- Usa
- KeyStore errors: Ensure you have proper write permissions to the keystore directory.
- Java version compatibility: Confirm you're using Java 11 or newer.
- JSON parsing errors: Check for syntax errors in your input JSON files.
- Missing credentials: Use the
info
command to check available credentials.
- Use
--verbose
to get detailed logging and error information. - Examine the output of
info --verbose
to check credential status. - For attestation issues, review the decoded attestation object details.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
- Improved: Dependency management to avoid downloading SNAPSHOTs from nexus mirror
- Enhanced: Simplified challenge handling during registration process
- Improved: Better handling of challenges during registration
- New: Enhanced Base64 encoding/decoding utilities
- Debug: More detailed logging for challenge tracking
- Performance: JSON processing optimization
- Added support for
CommandHandler
interface replacingCredentialHandler
- Enhanced
info
command with detailed system configuration output - Changed --file option to --input for consistency
- Improved error handling and documentation
- Initial release with core FIDO2 functionality
- Support for registration and authentication
© 2025 Jordi Murgo (jordi.murgo@gmail.com). FIDO2 Client Simulator. MIT License.