Skip to main content

Manage certificates

This guide shows you how to generate self-signed certificates for development and configure production certificates for the Truvity EUDIW Connector. Certificates authenticate the connector to EUDI Wallets and establish your identity as a registered Relying Party or credential issuer.

Prerequisites
  • A running connector instance, or one you are preparing to deploy. See connector architecture for the deployment model.
  • A tool that can generate EC P-256 keys and X.509 certificates (the examples below use openssl, available by default on macOS and most Linux distributions)
  • For production: an X.509 access certificate from a Certificate Authority (CA) or member state registrar

Overview

The connector uses certificates for both verification and issuance. This guide covers all certificate types.

Verification requires two certificate types:

  • Access certificates are X.509 certificates that authenticate the connector to wallets. The connector includes the access certificate in the x5c header of the signed authorization request JWT, as required by the HAIP profile. The wallet verifies your access certificate against trust lists before showing the consent screen to the user.
  • Registration certificates are signed data objects (JWT or CWT format, not X.509) that prove your organization's registration as a Relying Party with member state authorities. Whether a registration certificate is required depends on the member state's policy. You obtain these through the member state's registration process when required.

Issuance requires additional certificates:

  • Issuer Signing Certificate signs the credentials your organization issues (covered in Issuance certificates below)
  • Access Certificate (for issuance) signs the credential issuer metadata
  • Registration Certificate (optional) declares which credential types you can issue

You are responsible for obtaining, renewing, and rotating your access certificate. The connector loads the certificate and private key from the file system (typically Kubernetes secret volumes) at startup.

Time to implement: 30 minutes for test certificates, 1-2 days for production certificates (depending on CA turnaround).

Step 1: Generate self-signed test certificates

Generate a self-signed EC P-256 key pair and X.509 certificate for development. EC P-256 is required because the HAIP profile mandates ES256 for signing authorization request JWTs. You can use any tool that produces PEM-format EC P-256 keys—the example below uses openssl.

# Generate an EC P-256 private key
openssl ecparam -genkey -name prime256v1 -noout \
-out ./certs/access-key.pem

# Generate a self-signed X.509 certificate (valid for 365 days)
openssl req -new -x509 -key ./certs/access-key.pem \
-out ./certs/access-cert.pem \
-days 365 \
-subj "/CN=My Organization/O=My Organization/C=DE"

The commands generate:

  • An EC P-256 private key in PEM format
  • A self-signed X.509 certificate in PEM format with a one-year expiration

Verify the generated certificate:

openssl x509 -in ./certs/access-cert.pem -text -noout

Configure the connector to load the certificate and key by setting the file paths in the connector's environment variables:

  • CONNECTOR_CERT_PATH—path to the PEM-encoded X.509 certificate file
  • CONNECTOR_KEY_PATH—path to the PEM-encoded private key file

For example, if you placed the files in ./certs/:

export CONNECTOR_CERT_PATH=./certs/access-cert.pem
export CONNECTOR_KEY_PATH=./certs/access-key.pem

The connector reads these files at startup.

Step 2: Configure production certificates

For production, obtain an X.509 access certificate from a CA or your member state's registrar.

Obtain the certificate

  1. Generate a Certificate Signing Request (CSR) using the connector's key pair or your own EC P-256 key. The HAIP profile requires ES256, so the key must use the P-256 curve.
  2. Submit the CSR to your CA or member state registrar.
  3. Receive the signed X.509 certificate in PEM format.

Load certificates from Kubernetes secrets

Store the certificate and private key as a Kubernetes secret:

kubectl create secret tls connector-access-cert \
--cert=./certs/access-cert.pem \
--key=./certs/access-key.pem \
-n your-namespace

Mount the secret as a volume in the connector's pod and set the environment variables to point to the mounted paths:

spec:
containers:
- name: connector
env:
- name: CONNECTOR_CERT_PATH
value: /var/secrets/x509/tls.crt
- name: CONNECTOR_KEY_PATH
value: /var/secrets/x509/tls.key
volumeMounts:
- name: x509-certs
mountPath: /var/secrets/x509
readOnly: true
volumes:
- name: x509-certs
secret:
secretName: connector-access-cert

Rotate certificates

When a certificate approaches expiration:

  1. Obtain a new certificate from your CA or registrar.
  2. Update the Kubernetes secret with the new certificate and key.
  3. Restart the connector pod to load the new certificate.

Plan certificate rotation before expiration to avoid service interruption. Wallets reject requests signed with expired certificates.

Issuance certificates

The following certificates are used for credential issuance, in addition to the verification access certificate.

Issuer signing certificate

The Issuer Signing Certificate is an X.509 certificate used to sign SD-JWT Verifiable Credentials during issuance. The connector includes this certificate in the credential's x5c header so that wallets can verify the credential signature against the issuer's certificate chain.

Key requirements:

  • Uses ES256 (P-256), the same curve as the verification access certificate
  • Must use a separate key from the verification access certificate
  • The PEM certificate file must contain the leaf certificate first, followed by any intermediate certificates, excluding the root. The connector builds the x5c header from this chain automatically.
  • Self-signed certificates are supported for development only

Generate a self-signed issuer signing certificate

Generate a self-signed EC P-256 key pair and certificate for development, following the same pattern as the verification access certificate in Step 1.

# Generate an EC P-256 private key for credential signing
openssl ecparam -genkey -name prime256v1 -noout \
-out ./certs/signing-key.pem

# Generate a self-signed X.509 certificate (valid for 365 days)
openssl req -new -x509 -key ./certs/signing-key.pem \
-out ./certs/signing-cert.pem \
-days 365 \
-subj "/CN=My Organization Issuer/O=My Organization/C=DE"

Verify the generated certificate:

openssl x509 -in ./certs/signing-cert.pem -text -noout

Configure the connector to load the Issuer Signing Certificate and private key:

  • CONNECTOR_CERTIFICATES_SIGNING_CERT_PATH—path to the PEM-encoded Issuer Signing Certificate file
  • CONNECTOR_CERTIFICATES_SIGNING_KEY_PATH—path to the PEM-encoded private key file

For example:

export CONNECTOR_CERTIFICATES_SIGNING_CERT_PATH=./certs/signing-cert.pem
export CONNECTOR_CERTIFICATES_SIGNING_KEY_PATH=./certs/signing-key.pem

The connector reads these files at startup. In production, mount them from Kubernetes secrets following the same pattern as Step 2.

Separate keys required

The Issuer Signing Certificate and the verification access certificate must use separate keys. Do not reuse the same key pair for both purposes.

Access certificate for issuance

The Access Certificate proves the connector's participation in the EUDI ecosystem. In the issuance context, the connector uses the Access Certificate to sign the Credential Issuer Metadata served at GET /.well-known/openid-credential-issuer.

The Access Certificate for issuance must use a separate key from the Issuer Signing Certificate. It may be the same certificate as the verification access certificate or a separate one, depending on your deployment requirements.

Configure the connector to load the Access Certificate for metadata signing:

  • CONNECTOR_CERTIFICATES_ACCESS_CERT_PATH—path to the PEM-encoded Access Certificate
  • CONNECTOR_CERTIFICATES_ACCESS_KEY_PATH—path to the PEM-encoded private key for metadata signing

For example:

export CONNECTOR_CERTIFICATES_ACCESS_CERT_PATH=/secrets/access/cert.pem
export CONNECTOR_CERTIFICATES_ACCESS_KEY_PATH=/secrets/access/key.pem

Registration certificate (optional)

The Registration Certificate is an optional signed data object that declares the issuer's entitlements—which credential types the issuer is authorized to issue. Not all member states issue registration certificates.

Key characteristics:

  • JWT format (not X.509). The ARF also defines CWT as a possible format, but the connector currently supports JWT only.
  • Included by value in the Credential Issuer Metadata when available
  • Obtained through the member state's registration process

If you have a Registration Certificate in JWT format, configure the connector to load it:

  • CONNECTOR_CERTIFICATES_REGISTRATION_JWT_PATH—path to the Registration Certificate in JWT format

For example:

export CONNECTOR_CERTIFICATES_REGISTRATION_JWT_PATH=/secrets/registration/cert.jwt

The connector includes the Registration Certificate in the Credential Issuer Metadata response when this path is configured.

Testing

  • Self-signed certificate generates with openssl and the output files are valid PEM
  • Connector starts and loads the certificate from the configured path
  • Wallet accepts the connector's authorization request (in test environments with trust list overrides)
  • Production certificate is recognized by wallets against the member state trust list
  • Issuer Signing Certificate generates with openssl and the output files are valid PEM
  • Connector loads the Issuer Signing Key and certificate chain at startup
  • Issued credentials contain the correct x5c header with the Issuer Signing Certificate chain
  • Issuer Signing Certificate and verification access certificate use separate keys

Troubleshooting

Connector fails to start with certificate errors

Verify that the certificate and key files are in PEM format and that the key matches the certificate. Run openssl x509 -in cert.pem -noout -text to inspect the certificate and openssl ec -in key.pem -noout to verify the private key is a valid EC key.

Wallet rejects the authorization request

The wallet validates your certificate against the trust list of the relevant jurisdiction. In development, configure the wallet or test environment to trust your self-signed certificate. In production, verify that your CA-issued certificate is included in the member state's trust list.

Certificate expiration

Monitor certificate expiration dates and rotate before they expire. Use openssl x509 -in cert.pem -noout -enddate to check the expiration date.

Issued credentials fail wallet verification

Verify that the Issuer Signing Certificate PEM file is correctly ordered (leaf certificate first, intermediates next, excluding the root). The connector builds the x5c header automatically from the PEM chain. Confirm that the Issuer Signing Key matches the leaf certificate in the chain.

Credential Issuer Metadata signature invalid

The connector signs the Credential Issuer Metadata with the Access Certificate private key. Verify that the Access Certificate and its private key are correctly configured and that the key matches the certificate. Check that the Access Certificate uses a separate key from the Issuer Signing Certificate.

Next steps

Further reading