Certificates
Overview
X.509 certificates are used to bind a public key to an entity through the signature of a trusted Certificate Authority (CA). This enables wallet holders to know with whom they interact, and lets verifiers know that presented credentials are signed by trusted issuers.
Procivis One supports two certificate-based identifier types: certificate identifiers for credential issuance and verification, and CA identifiers for signing certificates for other entities.
There are four workflows depending on your setup.
| Goal | Workflow |
|---|---|
| Issue or verify credentials with a certificate signed by an external CA | Import a certificate |
| Issur or verify credentials with a certificate signed by a CA internal to the system | Create a certificate using an internal CA |
| Use an externally-signed CA to issue certificates to other entities | Import a CA certificate chain |
| Create your own root CA without external signing | Create a self-signed root CA |
Configuration
See the X.509 Signing Configuration guide.
Check if you can use certificates
Retrieve the configuration through the API and check two things:
Whether certificates are enabled in your system. The
identifierobject determines the types of identifier available to you:
"identifier": {
"CERTIFICATE": {
"display": "identifier.certificate",
"enabled": true,
"order": 1
},
"CA": {
"display": "identifier.ca",
"enabled": true,
"order": 2
}
},
Whether the credential format you want to work with is compatible with certificates. Formats have capabilities that specify which identifier types are compatible:
"format": {
"EXAMPLE_FORMAT": {
"capabilities": {
"issuanceIdentifierTypes": [
"DID",
"CERTIFICATE" // You can use certificates to issue credentials of this format
],
"verificationIdentifierTypes": [
"DID",
"CERTIFICATE" // You can use certificates to verify credentials of this format
],
},
"display": "format.example",
"type": "EXAMPLE_FORMAT"
}
}
Import a certificate
Certificate identifiers are used for issuing and verifying credentials. This workflow involves creating a key pair, obtaining a signed certificate from an external CA, then importing it as an identifier.
1. Create a key pair
Generate an ECDSA or EDDSA key pair.
Related guide: Create a key pair
2. Create a CSR
Generate a Certificate Signing Request using your key. If you plan on issuing
ISO mDL (DocType: org.iso.18013.5.1.mDL), set the profile to MDL to add
the necessary extensions. Otherwise, set to GENERIC.
If you need to specify a DNS name in the Subject Alternative Name (SAN)
field - for example, when using the x509_san_dns client ID scheme for
OpenID4VP verification - include the DNS name when generating the CSR.
3. Get the CSR signed
Submit your CSR to a Certificate Authority that offers SHA256 signatures. This can be an external CA or a CA identifier you've created in the system. When your request is completed, download the signed certificate in PEM format.
4. Import the signed certificate
Create a new identifier with type CERTIFICATE. Provide the certificate chain
in PEM format and reference the key ID used to create the CSR. If your certificate
has no common name (CN), you must provide a name during identifier creation.
Example request body:
{
"name": "My Certificate Identifier",
"organisationId": "{{ORG-UUID}}",
"certificates": [
{
"chain": "-----BEGIN CERTIFICATE-----\nMIIDo.....\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIC6j....\n-----END CERTIFICATE-----\n",
"keyId": "{{KEY-UUID}}",
"name": "Optional certificate name"
}
]
}
The chain field must include the leaf certificate and can optionally include
intermediate and root certificates up the chain. The system validates that the
certificate is currently valid, that the referenced key matches the certificate's
public key, and that the chain is properly signed.
5. Use the certificate identifier
Once imported, use your certificate identifier for credential operations:
- Issuance: Reference the identifier UUID as the
issuerwhen creating a credential - Verification: Reference the identifier UUID as the
verifierwhen creating a proof request
Create a certificate using an internal CA
This workflow uses a CA identifier already in the system to sign your certificate, removing the need for external signing.
1. Create a key pair
Generate an ECDSA or EDDSA key pair.
Related guide: Create a key pair
2. Create a certificate identifier
Create a new identifier, providing certificate subject details and referencing both the key ID and the CA identifier to sign the certificate.
Example request body:
{
"organisationId": "{{ORG-UUID}}",
"name": "Certificate Identifier",
"certificates": [
{
"content": {
"certificateAuthority": {
"identifierId": "{{CA-IDENTIFIER-UUID}}"
},
"profile": "GENERIC",
"signer": "X509_CERTIFICATE", // Reference a configured instance
"subject": {
"commonName": "Acme Issuer",
"countryName": "CH",
"organisationName": "Acme Corporation"
},
"validityStart": "2026-07-22T00:00:00Z",
"validityEnd": "2027-07-21T00:00:00Z"
},
"keyId": "{{KEY-UUID}}",
"name": "Optional certificate name",
"roles": [
"AUTHENTICATION",
"ASSERTION_METHOD"
]
}
]
}
You can optionally specify a DNS name in the Subject Alternative Name (SAN)
field. This is required when using the x509_san_dns client ID scheme,
where the verifier's domain name must match the certificate's SAN DNS entry.
3. Use the certificate identifier
Use your certificate identifier for credential operations:
- Issuance: Reference the identifier UUID as the
issuerwhen creating a credential - Verification: Reference the identifier UUID as the
verifierwhen creating a proof request
Import a CA certificate chain
If you have a CA certificate signed by an external authority, you can import it as a CA identifier.
1. Create a key pair
Generate an ECDSA or EDDSA key pair.
Related guide: Create a key pair
2. Create a CSR
Generate a Certificate Signing Request using the CA profile to include
appropriate CA extensions.
3. Get the CSR signed externally
Submit your CSR to an external Certificate Authority. When completed, download the full certificate chain in PEM format.
4. Import the CA chain
Create a new identifier, providing the full certificate chain where the leaf certificate is your CA certificate.
Example request body:
{
"name": "My CA Identifier",
"organisationId": "{{ORG-UUID}}",
"certificateAuthorities": [
{
"chain": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n",
"keyId": "{{KEY-UUID}}",
"name": "Optional CA name"
}
]
}
The system validates that the leaf certificate is a CA certificate (with
CA:TRUE in basic constraints), that it's signed by the specified key,
and that the chain is properly signed.
Create a self-signed root CA
To create your own root CA without external signing, you can generate a self-signed CA certificate directly.
1. Create a key pair
Generate an ECDSA or EDDSA key pair.
Related guide: Create a key pair
2. Create the self-signed CA identifier
Create a new identifier, providing certificate subject details and validity period. The system generates and self-signs the CA certificate.
Example request body:
{
"name": "My Root CA",
"organisationId": "{{ORG-UUID}}",
"certificateAuthorities": [
{
"keyId": "{{KEY-UUID}}",
"name": "Optional CA name",
"selfSigned": {
"content": {
"commonName": "Acme Root CA",
"organization": "Acme Corporation",
"country": "CH"
},
"signer": "X509_CERTIFICATE",
"validityStart": "2025-01-01T00:00:00Z",
"validityEnd": "2035-01-01T00:00:00Z"
}
}
]
}
The system creates a self-signed CA certificate with the specified subject information and validity period.
mdoc CAs require an issuer alternative name in the certificate content. Add
the issuerAlternativeName object to content with a type of EMAIL or
URI and a corresponding name value:
"content": {
"commonName": "Acme mdoc Root CA",
"organization": "Acme Corporation",
"country": "CH",
"issuerAlternativeName": {
"type": "URI",
"name": "https://acme.example.com"
}
}
Ensure the signer value references an X509_CERTIFICATE instance
configured for mdoc CA issuance.
Certificate and CA status
Retrieve the identifier detail and check the state field for status:
ACTIVE or DEACTIVATED. Certificates and CAs are active unless none of
the certificates are currently valid.
You can run a task (typically a cronjob) using the Core API with the following request body to update certificate status:
{
"name": "CERTIFICATE_CHECK"
}
Editing certificate identifiers
Adding certificates
You can add certificates to a certificate identifier by using
POST /api/identifier/v1/{identifierId}/certificate. The shape matches
the one used to create a certificate identifier, including either
importing a certificate or creating one using an internal CA. See the
following for guidance:
The call returns the ID(s) of the new certificate(s). Once added, you can
use a new certificate by specifying it in fields such as issuerCertificate
and verifierCertificate, for example:
POST /api/credential/v1
{
"issuer": "<IDENTIFIER-ID>",
"issuerCertificate": "<NEW-CERTIFICATE-ID>", // Omit this to let the system select which certificate to use
...,
}
If the identifier is in state DEACTIVATED and a new valid certificate
is added, the identifier state changes to ACTIVE.
Removing certificates
You can remove certificates from a certificate identifier by using
DELETE /api/identifier/v1/{identifierId}/certificate/{certificateId}.
A deleted certificate is removed from the identifier but can still be
accessed at GET /api/certificate/v1/{id}, and is not removed from any
other identifier to which it is linked.
If a DELETE call would remove all certificates from an identifier the
call fails.
For any given identifier, if all Access Certificates of an ETSI identifier
are deleted then the Registration Certificates (found in trustInformation)
of the same ETSI identifier are also removed from the identifier.
Editing certificate authority identifiers
Adding CAs
You can add certificate authorities to a CA identifier by using
POST /api/identifier/v1/{identifierId}/certificate-authority. The shape
matches the one used to create a CA identifier, including either importing
a CA certificate chain or creating a self-signed root CA. See the following
for guidance:
The call returns the ID(s) of the new CAs. Once added, you can use a new CA
by using certificateId when creating a new certificate identifier:
{
"certificates": [
{
"content": {
"certificateAuthority": {
"identifierId": "<IDENTIFIER-ID>",
"certificateId": "<NEW-CA-ID>" // Omit this to let the system select which CA to use
},
...
},
}
]
}
If the identifier is in state DEACTIVATED and a new valid CA is added,
the identifier state changes to ACTIVE.
Removing CAs
You can remove certificate authorities from a CA identifier by using
DELETE /api/identifier/v1/{identifierId}/certificate-authority/{certificateAuthorityId}.
A deleted CA is removed from the identifier but can still be
accessed at GET /api/certificate/v1/{id}, and is not removed from any
other identifier to which it is linked.
If a DELETE call would remove all CAs from an identifier the call fails.