Key Management - Signing Keys and Certificates
The Organisation Wallet Suite signs with the keys of your organisation. A key has one of four purposes, and you set each one in a different request:
| Key | What it signs | Where you set it | Certificate profile |
|---|---|---|---|
| Credential signing key | The credentials that you issue (SD-JWT VC, W3C VC, mso_mdoc) | Credential definition: cryptographicKeyFormat and cryptographicKeyIdentifier, for the whole definition or for one entry of credentialDefinitions | Credential issuer; mdoc issuer (Document Signer) for mso_mdoc |
| Status list signing key | The status list token that tells verifiers if a credential is revoked or suspended | Credential definition, in an entry of credentialDefinitions: statusListCryptographicKeyFormat and statusListCryptographicKeyIdentifier. Leave them out to use the credential signing key | Credential issuer. For mso_mdoc: x509 from the same CA as the Document Signer, without extended key usage (ISO/IEC 18013-5 Table B.9) |
| Verification request signing key | The OpenID4VP request object of a verifier | Presentation definition: cryptographicKeyFormat and cryptographicKeyIdentifier | Relying party (WRPAC); mdoc verifier for ISO/IEC 18013-7 Annex C |
| Issuer metadata signing key | The Credential Issuer Metadata, when you publish it signed (signed_metadata) | Global configuration: issuerMetadata.signedMetadataEnabled, issuerMetadata.cryptographicKeyFormat and issuerMetadata.cryptographicKeyIdentifier | Credential issuer |
Each key signs with did:key or with x509. With x509 the signature carries the certificate chain (x5c), and EUDI Wallets check it against a trust list: an issuer list (EAA, QEAA, Pub-EAA or PID) for the credential, status list and metadata keys, and the WRPAC list for the verification request key. When the certificate is on the list, the wallet shows your organisation as trusted. Use did:key for tests only. mso_mdoc always needs x509.
Choosing a key in a workflow: in the request panels of the developer guides, each signing key field has a key label next to it, for example Credential signing key after cryptographicKeyIdentifier. Click it to list the keys from Step 7, see which have a certificate and its profile, and write the key into that field and its format field. A credential definition can have a different key for each purpose. Hover a field name to see what the field does.
This guide creates a key and gives it a certificate:
- Configure the secure vaults that hold the keys.
- Create a key.
- Generate a certificate signing request (CSR) for the key.
- Get an X.509 certificate for the CSR, with the profile of the purpose.
- Upload the certificate chain to the key.
- List the keys and check which ones have a certificate.
- Register the certificate in a trust list.
Step 1: Get the API Key (Admin)
To obtain your API key, please contact [email protected]. Once you have received your API key, enter it in the field below and click the Set API Key button to save it for future use.
Step 2: Configure the Secure Vaults (Admin)
A secure vault holds the private keys. The private key never leaves the vault: the API returns public keys only. Your organisation can use these vaults:
| Key management service | Use it when |
|---|---|
| Local Vault | You want the platform to hold the keys. Always enabled. |
| External Vault | Your keys are in your own Hashicorp Vault. |
| Qualified Trust Service Provider (QTSP) | You sign qualified electronic signatures with a QTSP over the Cloud Signature Consortium (CSC) API. |
Read the current configuration first. Then select a sample, change it to your values, and run it. Every organisation starts with the Local Vault, so this step uses the Update Secure Vault API (PUT). The Configure Secure Vault API (POST) works only for an organisation without a vault configuration.
Read the configuration
Request
Response
Update the vaults
Request
Response
For a QTSP, select the signing credential after this step with the List QTSP Credentials and Configure QTSP Credential APIs. The QTSP holds that key, so Steps 3 to 5 do not apply to it.
Step 3: Create a Key (Admin)
Create an ECDSA P-256 key in the Local Vault (vaultType 1). The API does not create keys in an External Vault or at a QTSP. The vault sets the key type, the curve (P-256) and the algorithm (ES256). Run the request. Alternatively, use the Create Key API. The response has the keyId, which the next steps fill in for you.
Request
Response
Step 4: Generate a CSR (Admin)
The certificate signing request (CSR) carries the public key of the key from Step 3 and the details of your organisation. commonName is required. organization, country (2 letter code), sanDns and sanUri are optional in the API, but give country: the certificate profiles below need it, and ISO/IEC 18013-5 requires it for mdoc. Put the domain of your service in sanDns: the x509_san_dns client ID prefix of OpenID4VP needs it. Alternatively, use the Generate CSR API.
Request
Response
Step 5: Get a Certificate for the CSR
For production, send the CSR to your Certificate Authority (CA) or QTSP, and ask for the certificate profile of your use. For tests, use one of the two options below. Both give a chain with the leaf certificate first, then the CA certificate. That is the order that Step 6 needs.
Select the certificate profile for what the key signs:
| Profile | Use the key for | Extensions of the leaf certificate |
|---|---|---|
| Credential issuer | SD-JWT VC and W3C VC credentials (PID, EAA, QEAA, Pub-EAA), status lists, signed issuer metadata | Base set |
| mdoc issuer | mso_mdoc credentials, such as mDL (ISO/IEC 18013-5 Document Signer) | Base set, extended key usage 1.0.18013.5.1.2 (critical), CRL distribution point |
| Relying party | Signed OpenID4VP requests of a verifier (WRPAC, ETSI TS 119 411-8) | Base set, extended key usage clientAuth, certificate policy 0.4.0.194118.1.2 |
| mdoc verifier | ISO/IEC 18013-7 Annex C requests (ISO/IEC 18013-5 reader authentication) | Base set, extended key usage 1.0.18013.5.1.6 (critical) |
| mdoc status list signer | Status lists of mso_mdoc credentials (ISO/IEC 18013-5 Table B.9) | Base set, signed by the same CA as the Document Signer. Use the credential issuer profile |
The base set for every profile: key usage digitalSignature (critical), subject and authority key identifiers, the subject alternative names of the CSR, an issuer alternative name with a contact email, and no basic constraints. The test CA has the shape of an ISO/IEC 18013-5 IACA root: country in the subject, basic constraints CA:TRUE with path length 0, key usage keyCertSign and cRLSign, and an issuer alternative name. The leaf is valid for 397 days, within the 457 days that ISO/IEC 18013-5 allows a Document Signer.
Option A: test CA in your browser
Select the profile and choose Sign CSR. The page creates a test CA in your browser and signs the CSR from Step 4 with it. Every key that you sign on this page chains to the same test CA, until you reload the page. Nothing leaves the page.
test-ca.pem if you want to keep the CA certificate.CSR
Certificate chain
Option B: test CA on your machine with OpenSSL 3
Save the CSR from Step 4 as request.csr, then run:
# 1. Create a test CA (once), in the shape of an ISO/IEC 18013-5 IACA root.
# Use the country of your CSR.
openssl ecparam -name prime256v1 -genkey -noout -out test-ca.key
openssl req -x509 -new -key test-ca.key -sha256 -days 825 -out test-ca.pem \
-subj "/C=SE/CN=My Test CA" \
-addext "basicConstraints=critical,CA:TRUE,pathlen:0" \
-addext "keyUsage=critical,keyCertSign,cRLSign" \
-addext "subjectKeyIdentifier=hash" \
-addext "issuerAltName=email:[email protected]"
# 2. The base set of extensions for every leaf certificate
cat > leaf.ext <<'EXT'
keyUsage=critical,digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
issuerAltName=email:[email protected]
EXT
# 3. Add the lines of your profile to leaf.ext (credential issuer: add nothing)
# mdoc issuer (Document Signer):
# extendedKeyUsage=critical,1.0.18013.5.1.2
# crlDistributionPoints=URI:https://example.com/crl/test-ca.crl
# Relying party (WRPAC):
# extendedKeyUsage=clientAuth
# certificatePolicies=0.4.0.194118.1.2
# mdoc verifier (reader authentication):
# extendedKeyUsage=critical,1.0.18013.5.1.6
# 4. Check the CSR, then sign it. -copy_extensions keeps the subject alternative names of the CSR.
openssl req -in request.csr -noout -verify
openssl x509 -req -in request.csr -CA test-ca.pem -CAkey test-ca.key -CAcreateserial \
-days 397 -sha256 -copy_extensions copy -extfile leaf.ext -out leaf.pem
# 5. Build the chain: leaf first, then the CA. Then check it.
cat leaf.pem test-ca.pem > chain.pem
openssl verify -CAfile test-ca.pem leaf.pem
openssl x509 -in leaf.pem -noout -text
Step 6: Upload the Certificate Chain (Admin)
Upload the chain to the key. The key ID and the chain from the earlier steps are filled in for you; you can also paste your own. The file must be PEM text with the leaf certificate first, then the intermediate certificates, then the root certificate. Alternatively, use the Upload Certificate Chain API.
The service refuses the file when it holds a private key, when the leaf certificate does not use the P-256 curve, when a certificate is expired or not yet valid, or when a chain signature is not correct.
Request
Response
The same request with curl:
curl -X POST "https://demo-api.igrant.io/v2/config/digital-wallet/openid/key-management/keys/$KEY_ID/certificate-chain" \
-H "Authorization: ApiKey $API_KEY" \
-F "[email protected]"
The response has key_id, certificates_count, x5t and x5t_s256. The key now has the chain as its x5c value.
Step 7: List the Keys (Admin)
List the keys of all vaults. Each key has its public JWK, isDefault (the wallet signs with this key by default) and its DIDs. A key with a certificate chain has x5c, x5t and x5t#S256 in its JWK. Alternatively, use the List Keys API.
Request
Response
Step 8: Register the Certificate in a Trust List
A wallet trusts your organisation when your certificate is on a trust list. To add your certificate to the NXD trust list, follow Register as a Wallet-Relying Party and send the request to [email protected]. Use the leaf certificate from Step 5. To learn how trust lists work, see Trust in the Wallet Ecosystem.
| You are | Trust list |
|---|---|
| Issuer of (Q)EAAs, Pub-EAAs or PIDs | EAA, QEAA, Pub-EAA or PID list |
| Verifier (relying party) | Wallet-Relying Party Access Certificate (WRPAC) list |