A secure and efficient key ownership proof system implemented in Rust, using JWT (JSON Web Tokens) and ES256 (ECDSA with P-256 curve) for digital signatures. The system consists of a verifier service and a holder client that demonstrate cryptographic proof of key ownership.
The system implements a challenge-response protocol where:
- A holder requests a nonce from the verifier
- The holder signs the nonce with their private key
- The verifier validates the signature using the holder's public key
-
Verifier Service (
src/main.rs
): A web service that:- Generates secure nonces
- Validates JWT signatures
- Prevents replay attacks
- Exposes REST API endpoints
-
Holder Client (
src/bin/holder.rs
): A client that:- Generates ES256 key pairs
- Requests nonces from the verifier
- Creates and signs JWTs
- Demonstrates key ownership
- Rust and Cargo (latest stable version)
- Docker and Docker Compose (for containerized deployment)
- OpenSSL development packages
-
Build the project:
cargo build
-
Start the verifier service:
cargo run --bin verifier
The service will start on
http://0.0.0.0:8080
-
Run the holder client:
cargo run --bin holder
- Build and start the services:
This will start both the verifier and holder services in containers.
docker-compose up --build
-
GET /api/nonce
- Generates a new nonce for signing
- Returns:
{"nonce": "<uuid-v4>"}
-
POST /api/verify
- Verifies a signed JWT and nonce
- Request body:
{"jwt": "<signed-token>", "public_key_pem": "<public-key>"}
- Returns:
{"verified": boolean, "message": "string"}
-
GET /api/list-nonces
- Lists all used nonces (for debugging)
- Returns:
{"nonce_count": number, "nonces": ["string"]}
-
POST /api/clear-nonces
- Clears the used nonces store
- Returns:
{"message": "string"}
-
Cryptographic Security
- Uses ES256 (ECDSA with P-256 curve and SHA-256)
- Implements industry-standard JWT format
- Private keys never leave the holder
-
Replay Attack Prevention
- Tracks used nonces in memory
- Rejects previously used nonces
- Implements nonce clearing mechanism
Key dependencies from Cargo.toml
:
actix-web
: Web frameworkjwt-simple
: JWT implementationjsonwebtoken
: JWT validationserde
: Serializationuuid
: Nonce generationreqwest
: HTTP client
To generate ES256 (ECDSA with P-256 curve) key pairs locally using OpenSSL, follow these steps:
-
Generate Private Key
# Generate a private key using the P-256 curve openssl ecparam -name prime256v1 -genkey -noout -out private.pem
-
Extract Public Key
# Derive the public key from the private key openssl ec -in private.pem -pubout -out public.pem
-
Convert to PKCS8 Format (for JWT.io compatibility)
# Convert the EC private key to PKCS8 format openssl pkcs8 -topk8 -nocrypt -in private.pem -out private_pkcs8.pem
-
Verify Key Format
# View the private key content (keep this secure!) openssl ec -in private.pem -text -noout # View the public key content openssl ec -in public.pem -pubin -text -noout
The generated keys will be in PEM format. Use the PKCS8 format private key (private_pkcs8.pem
) with JWT.io for manual testing, and the original EC private key (private.pem
) with the holder client.
You can use JWT.io to manually generate and verify JWTs for testing and understanding the token structure:
-
Header Setup
- Algorithm: Select "ES256" (ECDSA with P-256 and SHA-256)
- The header will look like:
{"alg": "ES256", "typ": "JWT"}
-
Payload Configuration
- Add the nonce received from the verifier
- Example payload:
{"nonce": "<received-nonce>", "exp": <170000000>}
-
Signature Process
- Paste your ES256 private key in PEM format
- The public key will be used for verification
- JWT.io will automatically generate the signature
-
Token Verification
- Paste the complete JWT token
- Input the public key in PEM format
- JWT.io will verify the signature integrity
The system implements comprehensive error handling:
- JWT validation errors
- Invalid public key format
- Network communication errors
- Nonce reuse attempts
Uses the env_logger
crate for configurable logging:
- Set
RUST_LOG=info
for standard logs - Set
RUST_LOG=debug
for detailed debugging
Logs include:
- API request handling
- Nonce generation and validation
- JWT verification results
- Error conditions