Skip to content

Key ManagementΒΆ

The keys used for signing operations in EUDIPLO can be managed by one or more KMS (Key Management System) providers running simultaneously. Providers are configured in a single kms.json file inside the config folder.

πŸ’‘ Encryption operations always use database-stored keys and are independent from the KMS providers configured for signing.

Available ProvidersΒΆ

Provider Type Description Import Support
db Built-in Keys stored encrypted in the database βœ… Yes
vault Built-in HashiCorp Vault Transit secrets engine ❌ No
aws-kms Built-in AWS Key Management Service ❌ No

ConfigurationΒΆ

KMS providers are configured in <CONFIG_FOLDER>/kms.json. If no file is found, a single db provider is registered automatically.

{
    "defaultProvider": "db",
    "providers": [
        { "id": "db", "type": "db", "description": "Default database provider" },
        {
            "id": "vault",
            "type": "vault",
            "description": "HashiCorp Vault",
            "vaultUrl": "http://localhost:8200",
            "vaultToken": "your-vault-token"
        },
        {
            "id": "aws",
            "type": "aws-kms",
            "description": "AWS KMS",
            "region": "eu-central-1"
        }
    ]
}
Field Description
defaultProvider ID of the provider used when no explicit kmsProvider is specified (default: db).
providers Array of provider configurations. Each entry must have a unique id and a type.

Each provider entry has:

Field Description
id Unique identifier for the provider instance (used when generating keys).
type Adapter type: db, vault, or aws-kms.
description Optional human-readable description.
... Additional type-specific configuration fields.

Environment-variable placeholders (${VAULT_URL}, ${VAULT_TOKEN:default}) are resolved at startup, so secrets can still be injected through the environment.

When generating or importing a key through the API, include the kmsProvider field to select a specific provider by its id. If omitted, the defaultProvider is used.

Multiple Providers of the Same TypeΒΆ

You can configure multiple instances of the same provider type with different IDs:

{
    "defaultProvider": "main-vault",
    "providers": [
        { "id": "db", "type": "db" },
        {
            "id": "main-vault",
            "type": "vault",
            "description": "Production Vault",
            "vaultUrl": "${VAULT_URL}",
            "vaultToken": "${VAULT_TOKEN}"
        },
        {
            "id": "backup-vault",
            "type": "vault",
            "description": "Backup Vault",
            "vaultUrl": "${BACKUP_VAULT_URL}",
            "vaultToken": "${BACKUP_VAULT_TOKEN}"
        }
    ]
}

Database Key Management (db)ΒΆ

When the db provider is configured (the default), keys are stored encrypted in the database. This mode is ideal for development or testing.

Key Chain SupportΒΆ

Each tenant can manage multiple key chains simultaneously. Each key chain has a unique ID and is isolated via the tenant_id field.

Key chains are unified entities containing both keys and certificates, organized by usage type (access, attestation, trustList, statusList, encrypt).


Vault (HashiCorp Vault)ΒΆ

To use HashiCorp Vault for key management, add a vault entry to the providers array in kms.json:

{
    "defaultProvider": "vault",
    "providers": [
        { "id": "db", "type": "db" },
        {
            "id": "vault",
            "type": "vault",
            "description": "HashiCorp Vault",
            "vaultUrl": "http://localhost:8200",
            "vaultToken": "your-vault-token"
        }
    ]
}
Field Description
vaultUrl Base URL of the Vault server (without /v1/…).
vaultToken Authentication token for Vault API access.

You can use environment-variable placeholders to avoid storing secrets in the config file:

{
    "id": "vault",
    "type": "vault",
    "vaultUrl": "${VAULT_URL}",
    "vaultToken": "${VAULT_TOKEN}"
}

Transit Mount Auto-CreationΒΆ

For each tenant, a transit secret engine mount is created automatically on first use. If the mount already exists the creation step is silently skipped (idempotent). If a Vault API call returns 404 (mount not found), the service retries the operation once after creating the mount.

To issue credentials, you need to have a signed certificate for the public key that is bound to your domain.

In this mode:

  • All signing operations are delegated to Vault via its API.
  • The private key never leaves the Vault server.
  • A stub key entity is stored in the database for tracking purposes (no private key material).
  • Access can be tightly controlled using Vault's policies and authentication mechanisms.

Vault is well-suited for production environments where secure, auditable key usage is required.


AWS KMSΒΆ

To use AWS Key Management Service for key management, add an aws-kms entry to the providers array in kms.json:

{
    "defaultProvider": "aws",
    "providers": [
        { "id": "db", "type": "db" },
        {
            "id": "aws",
            "type": "aws-kms",
            "description": "AWS KMS",
            "region": "eu-central-1"
        }
    ]
}
Field Description
region AWS region where KMS keys will be created (required).
accessKeyId AWS access key ID (optional β€” uses SDK credential chain if not provided).
secretAccessKey AWS secret access key (optional β€” uses SDK credential chain if not provided).

You can use environment-variable placeholders to avoid storing secrets in the config file:

{
    "id": "aws",
    "type": "aws-kms",
    "region": "${AWS_REGION}",
    "accessKeyId": "${AWS_ACCESS_KEY_ID}",
    "secretAccessKey": "${AWS_SECRET_ACCESS_KEY}"
}

AuthenticationΒΆ

If accessKeyId and secretAccessKey are not provided, the adapter uses the AWS SDK default credential chain, which supports:

  • Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
  • Shared credentials file (~/.aws/credentials)
  • IAM roles for EC2/ECS/Lambda
  • Web identity tokens (EKS IRSA)

This is the recommended approach for production deployments.

Key CreationΒΆ

Keys are created as asymmetric ECC_NIST_P256 keys with SIGN_VERIFY usage. Each key is tagged with:

  • TenantId β€” the tenant identifier
  • LocalKeyId β€” the local key ID stored in the database
  • ManagedBy β€” set to eudiplo

Key DeletionΒΆ

When deleting a key, AWS KMS schedules it for deletion with a 7-day pending window (the minimum allowed by AWS). The local database reference is removed immediately.

In this mode:

  • All signing operations are delegated to AWS KMS via its API.
  • The private key never leaves AWS KMS.
  • A stub key entity is stored in the database for tracking purposes (no private key material).
  • Access can be controlled using AWS IAM policies and KMS key policies.

AWS KMS is well-suited for production environments on AWS where you need HSM-backed keys, audit logging via CloudTrail, and fine-grained access control.

⚠️ Note: AWS KMS does not support importing EC keys. Use create to generate new keys directly in AWS KMS.


ExtensibilityΒΆ

The key management system is designed to be extensible. You can integrate other key management backends such as:

  • βœ… AWS KMS (built-in)
  • πŸ” Azure Key Vault
  • πŸ” Google Cloud KMS
  • πŸ” Hardware Security Modules (HSMs)

To add a new backend:

  1. Create a new class extending KmsAdapter (see aws-kms-key.service.ts or vault-key.service.ts for reference).
  2. Register a factory function for the new type in kms-adapter.factory.ts.
  3. Add a config DTO in dto/kms-config.dto.ts extending BaseKmsProviderConfigDto.
  4. Add the provider entry to kms.json:
{
    "providers": [
        {
            "id": "azure",
            "type": "azure-kv",
            "description": "Azure Key Vault",
            "vaultUrl": "https://my-vault.vault.azure.net",
            "tenantId": "...",
            "clientId": "..."
        }
    ]
}

If you need help integrating a new provider, feel free to open an issue or contact the maintainers.


Key ChainsΒΆ

EUDIPLO uses a unified Key Chain model that combines cryptographic keys and their certificates into a single managed entity. This eliminates orphaned keys and simplifies key lifecycle management.

Key Chain ModelΒΆ

A Key Chain encapsulates:

  • Active signing key with its certificate
  • Optional root CA key (for internal certificate chains / rotation)
  • Previous key (for grace period after rotation)
  • Rotation policy (automatic certificate renewal)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               Key Chain                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Root CA Key (optional)                      β”‚
β”‚  Root CA Certificate (self-signed)           β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Active Signing Key                          β”‚
β”‚  Active Certificate (CA-signed or self)      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Previous Key (optional, grace period)       β”‚
β”‚  Previous Certificate                        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Rotation Policy                             β”‚
β”‚  - Interval Days                             β”‚
β”‚  - Certificate Validity Days                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Usage TypesΒΆ

Each key chain is assigned a usage type that determines how it can be used:

Usage Type Purpose
access OAuth/OIDC access token signing and authentication
attestation Credential/attestation signing (SD-JWT VC, mDOC)
trustList Trust list signing
statusList Status list (credential revocation) signing
encrypt Encryption (JWE)

Key Chain TypesΒΆ

Standalone Key Chain:

  • Single key with self-signed certificate
  • Suitable for development/testing
  • No rotation support

Internal CA Key Chain (Rotation Enabled):

  • Root CA key signs leaf certificates
  • Active key is separate from root CA
  • Supports automatic rotation
  • Satisfies HAIP section 4.5.1 requirement (credentials MUST NOT be signed with self-signed certificates)

Automatic Key Chain GenerationΒΆ

On startup, if no key chains are found for a tenant, the service automatically generates key chains for each required usage type:

  • access - For OAuth/OIDC operations
  • attestation - For credential signing

Certificate Chain SupportΒΆ

When using internal CA key chains, the certificate includes a full chain:

  1. Leaf certificate (signs credentials/tokens)
  2. Root CA certificate (signs leaf certificates)

This chain is included in the x5c header of signed tokens.

Certificate FormatΒΆ

Certificates must be in PEM format:

  • Use \n escape sequences in JSON
  • Include both -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- headers
  • Base64-encoded DER content between headers

Certificate ValidationΒΆ

Certificates are validated during import:

  • PEM format verification
  • Public key matching with associated key
  • Certificate expiration checking
  • X.509 standard compliance

When using the Registrar, it will generate a certificate for the public key that can be used to secure the OID4VCI and OID4VP requests.

Note: In the future the access certificate generation will follow the official standard that is under development right now.


Multi-Tenant Key ManagementΒΆ

Automatic Key Chain GenerationΒΆ

Tenant Initialization Process:

  1. Client registers with credentials (client_id, client_secret)
  2. Key chains automatically generated for each required usage type
  3. Keys and certificates stored in the unified key chain
  4. Certificates linked to keys in the same entity

Key Chain Import and ManagementΒΆ

EUDIPLO supports importing key chains through multiple methods to accommodate different deployment scenarios and security requirements.

API-Based Key Chain ImportΒΆ

Import key chains through the REST API using authenticated requests:

Endpoint: POST /key-chain

Request Body (Standalone - self-signed certificate):

{
    "id": "optional-uuid",
    "usageType": "attestation",
    "key": {
        "kty": "EC",
        "x": "pmn8SKQKZ0t2zFlrUXzJaJwwQ0WnQxcSYoS_D6ZSGho",
        "y": "rMd9JTAovcOI_OvOXWCWZ1yVZieVYK2UgvB2IPuSk2o",
        "crv": "P-256",
        "d": "rqv47L1jWkbFAGMCK8TORQ1FknBUYGY6OLU1dYHNDqU",
        "alg": "ES256"
    },
    "description": "Optional description"
}

Request Body (With Rotation - imported key becomes root CA):

{
    "id": "optional-uuid",
    "usageType": "attestation",
    "key": {
        "kty": "EC",
        "x": "pmn8SKQKZ0t2zFlrUXzJaJwwQ0WnQxcSYoS_D6ZSGho",
        "y": "rMd9JTAovcOI_OvOXWCWZ1yVZieVYK2UgvB2IPuSk2o",
        "crv": "P-256",
        "d": "rqv47L1jWkbFAGMCK8TORQ1FknBUYGY6OLU1dYHNDqU",
        "alg": "ES256"
    },
    "description": "HAIP-compliant key chain with CA-signed leaf",
    "rotationPolicy": {
        "enabled": true,
        "intervalDays": 90,
        "certValidityDays": 365
    }
}

When rotationPolicy.enabled is true:

  • The imported key becomes the root CA key
  • A new leaf signing key is automatically generated
  • The leaf certificate is signed by the imported CA key
  • This satisfies HAIP section 4.5.1 (credentials MUST NOT be signed with self-signed certificates)

Response:

{
    "id": "039af178-3ca0-48f4-a2e4-7b1209f30376"
}

Configuration-Based Key Chain ImportΒΆ

Import key chains automatically during application startup using the configuration import system.

Environment Variables:

CONFIG_IMPORT=true
CONFIG_IMPORT_FORCE=false  # Set to true to overwrite existing key chains

Directory Structure:

assets/config/
β”œβ”€β”€ tenant-1/
β”‚   └── key-chains/
β”‚       β”œβ”€β”€ attestation.json
β”‚       β”œβ”€β”€ access.json
β”‚       └── status-list.json
└── tenant-2/
    └── key-chains/
        └── attestation.json

Key Chain File Format (Standalone):

{
    "id": "uuid-for-this-key-chain",
    "description": "Attestation signing key chain",
    "usageType": "attestation",
    "key": {
        "kty": "EC",
        "x": "...",
        "y": "...",
        "crv": "P-256",
        "d": "...",
        "alg": "ES256"
    }
}

Key Chain File Format (With Rotation / Internal CA):

{
    "id": "uuid-for-this-key-chain",
    "description": "HAIP-compliant attestation key chain",
    "usageType": "attestation",
    "key": {
        "kty": "EC",
        "x": "...",
        "y": "...",
        "crv": "P-256",
        "d": "...",
        "alg": "ES256"
    },
    "rotationPolicy": {
        "enabled": true,
        "intervalDays": 90,
        "certValidityDays": 365
    }
}

Key Chain File Format (With Provided Certificate):

{
    "id": "uuid-for-this-key-chain",
    "description": "Key chain with external certificate",
    "usageType": "attestation",
    "key": {
        "kty": "EC",
        "x": "...",
        "y": "...",
        "crv": "P-256",
        "d": "...",
        "alg": "ES256"
    },
    "crt": [
        "-----BEGIN CERTIFICATE-----\nLEAF_CERT...\n-----END CERTIFICATE-----",
        "-----BEGIN CERTIFICATE-----\nCA_CERT...\n-----END CERTIFICATE-----"
    ]
}

Key Chain Management OperationsΒΆ

For detailed key chain management endpoints, parameters, and request/response schemas, see:

API Reference: Key Chain API Endpoints

Available operations include listing key chains, importing key chains, rotating keys, and managing key chain metadata.

Supported Key FormatsΒΆ

  • Algorithm Support: ES256 (ECDSA P-256)
  • Key Format: JSON Web Key (JWK) format
  • Certificate Support: Optional X.509 certificates in PEM format (leaf first, then CA chain)
  • Key Generation: Automatic generation if no key chains exist