- Overview
- Major changes from G3 to G4
- Certificate profiles
- Limitations
- Usage
- Requirements
- Support & Contributing
- Disclaimer
This tool allows you to generate TRIAL (test) certificates for the PKIoverheid G4 hierarchies yourself. It generates a complete hierarchy of certificates resembling a chosen G4 hierarchy. For more information on these hierarchies, please refer to the PKIoverheid CPS, Section 1.1.
G4 TRIAL end entity certificates for testing purposes can be acquired free of charge from the following organisation(s); however, when certificates are issued on physical tokens, a fee may apply.
Please note: only the PKIoverheid Trust Service Providers issue production PKIoverheid certificates. For more information see PKIoverheidcertificaat aanvragen (in Dutch).
To generate G4 TRIAL certificates yourself, there are two options:
- To validate your own (local) technical setup, download this repository and create the full hierarchies yourself;
- To use for integration testen ("ketentesten") and you intend to issue many TRIAL certificates (perhaps to suppliers) you may request a "fauxTSP" CA certificate for the common G4 TRIAL hierarchies. Please contact us to discuss in detail.
For the G3 certificate hierarchy some PKIoverheid TSPs offer TRIAL certificates. However, the G4 hierarchies consists of many different types of certificates, increasing implementation costs for TSPs. Therefore it was deemed most effective for users to be able to generate their own test certificates using a publicly available tool.
Software developers creating applications either using PKIoverheid certificates, or validating signatures created with PKIoverheid certificates, will be the primary audience of the PKIoverheid TRIAL certificates. However, organizations using commercial off the shelf (COTS) software in combination with PKIoverheid certificates or signatures created using them, may also wish to test their software stack with the PKIoverheid TRIAL certificates.
There have been a number of changes from G3 to G4, which you need to be aware of. In depth technical changes are described in the PKIoverheid CPS and Certificate Policy/Programme of Requirements PKIoverheid, while the functional changes are:
- Instead of one certificate public root (G3) and one private root (G1), the PKIoverheid G4 consists of multiple Certificate Roots, depending on its trust type (Public, Mandated (eIDAS) and Private). Since Privately trusted roots may be used separately within a specific domain, several Privately trusted Certificate Roots are created. Relying parties should only trust the appropriate Certificate Roots. Please see https://cert.pkioverheid.nl/ for details;
- Many more certificate types are available for the G4 than G3, the certificate issuers' Common Names reflect this accordingly;
- Intermediate CAs are based upon Subject Type (Natural Persons, Legal Entities or Devices), rather than a validation type, for example the G3's "Organisatie Persoon";
- No OCSP Service is offered for any of the G4 Root, Domain and TSP certificates. TSPs may still implement OCSP Services if desired;
- G3 certificates used a limited number of Policy OIDs, this has been expanded significantly for the G4. This allows the relying party to pinpoint exactly which type of certificate and validation was performed;
- G4 makes a distinction between Authenticity and Authentication certificates, while G3 only defined Authenticity for both use cases. Confidentiality and Authenticity usages for certificates are deemed an edge case and is disabled by default in the G4 TRIAL;
- Previously two variants existed of G1 Private Services Server certificate (OID: 2.16.528.1.1003.1.2.8.6). One containing one or more domain names and one without. This has been changed in G4. A "G4 Private Other Generic Legal Persons Organization Validated Authentication" does not contain any domains and is used only for
clientAuth. A "G4 Private TLS Generic Devices Organization Validated Server" contains one or more domains and can be used for bothclientAuthandserverAuth. - G3 certificates were allowed to have IP addresses as Subject Alternate Names (SAN). The G4 prohibits this.
- Signature algorithm
RSASSA‐PKCS1‐v1_5has been designated as legacy by the ECCG Agreed Cryptographic Mechanisms Guideline and is replaced byRSASSA-PSS. This algorithm is used for Certificate Signing Requests (CSR), certificates and CRLs. This may have an impact if TLS 1.2 is used.
The PKIoverheid G4 hierarchies offer many different types of certificates, each for a different purpose. Please refer to the factsheet Wees voorbereid de nieuwe generatie pkioverheidcertificaten komen eraan (Dutch) or New generation of PKIoverheid Certificates (English) for details.
The included profiles are compliant with:
- ETSI EN 319 412-1 V1.6.1 (Overview and common data structures)
- ETSI EN 319 412-2 V2.4.1 (Certificate profile for certificates issued to natural persons)
- ETSI EN 319 412-3 V1.3.1 (Certificate profile for certificates issued to legal persons)
- ETSI EN 319 412-4 V1.4.1 (Certificate profile for web site certificates)
- Certification Practice Statement Policy Authority PKIoverheid Unified v5.5
- PKIoverheid Programme of Requirements v5.2
Please be aware certificates generated by this tooling differ from their production counterparts in some aspects:
- There is no Certificate Policy document and as such these certificates provide no trust whatsoever.
- Serial Numbers are not generated using a CSPRNG.
- Issuer and Subject fields do not mention "Staat der Nederlanden" or any of the participating TSPs. Instead, "TRIAL PKIoverheid", "My TSP" and/or the name of a fauxTSP are used. Nevertheless, relying parties should not rely on Subject and Issuer fields for trust.
- Validity range for end entity certificates defaults to 397 days, which may be different from production certificates;
- Policy Identifiers are defined by the differentation model and differ slightly between TRIAL and Production, for example:
Certificate type TRIAL Production System Organization Validation Server 2.16.528.1.1003.1.2.*41*.15.39.112.16.528.1.1003.1.2.*44*.15.39.11 - TRIAL certificate profiles must be indicative of their production counterparts, as such any required
qcStatementsfor production certificates are also included in TRIAL certificates, even if they're undoubtedly false. For example, certificates may claim the private key resides on a Secure Signature Creation Device (SSCD) as indicated by theqcStatementid-etsi-qcs-QcSSCD, which is obviously false for test certificates. - To enable testing on a local machine, TRIAL certificates for private TLS may include
localhostas SubjectAlternateName (SAN). - There may be some minor (non-security) differences between these TRIAL certificates and certificates offered by the different PKIoverheid TSPs. Most notably the value of the
subject.commonNamefield and the ASN.1 encoding of somesubjectfields may be different.
All G4 TRIAL certificates are self issued and must not be used for any production purpose and should only be used for testing purposes.
Currently, only the following G4 Domains have been included:
- G4 Private TLS Generic Devices
- G4 Private Other Generic Natural Persons
- G4 Private Other Generic Legal Persons
- G4 EUTL Signatures Generic Natural Persons
- G4 EUTL Signatures Generic Legal Persons
If you require any other G4 Domain, please open a Github issue in this repository.
First you'll need to install the software. This can be done directly on your host OS, or use a Docker image.
- Clone this repository locally
- You will need Python >=3.10 installed. If not already installed, please follow the instructions for your operating system at https://www.python.org;
- To be able to install additional libraries, you will need to install
pip. For instructions please refer to https://packaging.python.org/en/latest/tutorials/installing-packages/; - (optional) create and activate a virtualenv, see previous hyperlink;
- Install the packages this repository requires:
pip install -r requirements.txt
Docker images of this tooling are automatically built and stored on Github Packages. You will need docker installed and configured on your system. To run the tooling, please refer to the example below.
# Create mountpoints
mkdir ca
touch config.yaml
# Pull image
docker pull ghcr.io/pkioverheid/g4-trial:latest
# Create a CA using an ephemeral docker container (see next step)
docker run -it --rm -v $(pwd)/ca:/app/ca -v $(pwd)/config.yaml:/app/config.yaml ghcr.io/pkioverheid/g4-trial:latest python create-ca.pyThis repository contains examples which allow you a quick look at G4 certificates.
The following commands will create a G4 TRIAL hierarchy for private TLS and one end entity certificate to secure a TLS endpoint on your local machine. If a Docker container is used these commands will vary slightly.
echo 1 | python create-ca.py
python generate-cert.py examples/enrollment/G4-Private-G-TLS-SYS-withOIN.yamlPrivate keys are placed in the ca/private directory and certificates are placed into the ca/certs.
There are two methods to initialise:
- By creating your own hierarchy (recommended for personal and isolated testing), or
- By joining the shared TRIAL hierarchy setup by Logius (recommended for integration testing).
- If you ran the Quick start, remove the
cadirectory to start fresh. - Update the URLs where issuing certificates and CRLs will be located after the initialization is complete. The example
config.yamlbelow allows you to host these files on your local machine, but you may host these files on your internal network for internal testing.caIssuersBaseUrl: http://localhost:8080/certs cRLDistributionPointsBaseUrl: http://localhost:8080/crl crlRenewalHours: 48
- Create the top three layers of the CA hierarchy for one or more G4 Domains. These are the self-signed Root CA, Domain CA and Issuing (fauxTSP) CA. This command will prompt which for which PKIoverheid G4 domain you'd like to create private keys, certificates and their (empty) Certificate Revocation Lists (CRL).
python create-ca.py
If you wish to join one or more shared TRIAL hierarchies, please reach out to us at pkioverheid@logius.nl so we can discuss the required steps.
This method allows you to create certificates operable with other providers of G4 TRIAL certificates.
- Determine for which domains you'd like to issue G4 TRIAL certificates;
- Locate the respective enrollment file in the
enrollmentdirectory:- G4 Private TLS Generic Devices:
TRIALMyTSPG4PKIoPrivGTLSSYS2025.yaml - G4 Private Other Generic Natural Persons:
TRIALMyTSPG4PKIoPrivGOtherNP2025.yaml - G4 Private Other Generic Legal Persons:
TRIALMyTSPG4PKIoPrivGOtherLP2025.yaml - G4 EUTL Signatures Generic Natural Persons:
TRIALMyTSPG4PKIoEUTLGSigsNP2025.yaml - G4 EUTL Signatures Generic Legal Persons:
TRIALMyTSPG4PKIoEUTLGSigsLP2025.yaml
- G4 Private TLS Generic Devices:
- Rename the enrollment file to replace "MyTSP" with your organization's name (letters only, no spaces), for example
TRIALMyTSPG4PKIoPrivGTLSSYS2025.yamlwould be renamed toTRIALMyOrganizationG4PKIoPrivGTLSSYS2025.yaml. This filename will be used to name the private key file and Certificate Signing Request (CSR) and must be unique within thecaandenrollmentdirectory. - Within the enrollment file, replace any occurrence of the string "My TSP" with your organization name (including spaces), for example "My Organization".
- Generate the Certificate Signing Requests (CSR) by running the command below and providing the files you edited:
Your enrollment will be validated, and when successful a private key and a CSR file will be created. The private key will be located within the
python create-csr.py <enrollment files>
ca/privatedirectory while the CSR will be saved to the current directory. - Send the CSR files to pkioverheid@logius.nl;
- PKIoverheid will reach out to you, discuss details and send your certificate(s);
- Place the certificate file(s) into the directory
ca/certs/ - Generate a boilerplate revocation file (which currently does not exist) and generate the first CRL for your certificate:
python generate-crl.py -f revocations/<enrollment filename>
Each end entity certificate requires subject information to be provided separately from the certificate profile. This information is provided using either an "enrollment" YAML file or a Certificate Signing Request (CSR). Please see any of the files in the examples/enrollment directory. The filename will indicate the certificate type. Please see the "G1/G3 to G4 mapping table" on the logius.nl website for information which certificate type you need for your use case.
If you modified the filename of the TSP CA enrollment file in previous steps, for example renaming "MyTSP" to "MyOrganization", you will need to modify the end entity certificate profiles accordingly since it contains a reference to this file. Below is an example how to modify the file for the G4 Private TLS Generic Devices end entity certificate profile specified in G4TRIALEEPrivGTLSSYS2025.yaml:
Old (snippet):
...
issuer: TRIALMyTSPG4PKIoPrivGTLSSYS2025.yaml
...New (snippet):
...
issuer: TRIALMyOrganizationG4PKIoPrivGTLSSYS2025.yaml
...When enrollment files are used, the fauxTSP generates the keypair and provides them to the subscriber. Enrollment files will need to be modified for your own use cases. An example enrollment file for G4 Private TLS Generic Devices could be:
---
profile: profiles/G4TRIALEEPrivGTLSSYS2025.yaml
subject:
C: NL
CN: Bedrijfsnaam TLS
O: Bedrijfsnaam
organizationIdentifier: NTRNL-99999991
serialNumber: 00000099123456789000
subjectAltNames:
- example.com
- www.example.comThe file indicates which certificate profile is to be used, provides subject information and (in this case) two FQDNs to be included in the certificate. This example uses both a KvK registration number in the organizationIdentifier field and a test OIN indicated by the 00000099 prefix in the serialNumber field. For each end entity certificate you want to create, create an appropriate enrollment file with an unique filename and modify it according to your needs. Then run:
python generate-cert.py <one or more enrollment files>Prior to generating the certificate, the script will validate your enrollment file against the requirements for the selected certificate profile and output any discrepancies. Please note that no validations are performed on the actual contents of each attribute, please refer to the documents listed under Certificate Profiles to determine what information should be included in each field.
The filenames of the newly generated private and public keys will match the filename of the enrollment file. They will be placed in the ca/private and the ca/certs directories, respectively. The command will not overwrite any preexisting files to prevent destruction of private keys.
A Subscriber usually generates a key pair themselves, encapsulates the public key alongside subject and subjectAlternateNames information into a PKCS #10 CSR. To generate the certificate using the default settings, run:
python sign-cert.py <CSR file>This will attempt to localize the appropriate certificate profile. If none or multiple are found an error is shown. Use the --profile flag to manually select the certificate profile to use.
Alternatively you can override the information provided in the CSR (except for the public key). Create an enrollment file as described in Option 1 and provide it to sign-cert.py using the --enrollment flag.
When CA certificates are created, an associated Certificate Revocation List (CRL) must be created. By default no certificates are revoked. However, to test revocation checking, you may want to generate some certificates and revoke them.
Each CA certificate will have a corresponding file in the revocations directory. For example:
---
revocations:
- serialNumber: '78:74:17:c2:a6:23:5f:55:57:ac:38:5e:e3:4d:6e:82:b4:fd:07:eb'
reason: superseded
date: "2025-08-08 00:00:00"
- serialNumber: '75:13:8e:39:29:93:c5:23:62:9f:bb:4c:24:dd:28:6b:41:11:52:c7'
reason: superseded
date: "2025-08-10 10:02:00"Only three values are needed per revocation:
serialNumberof the certificate must indicated in hexadecimal format separated by colons (openSSL format);reasonfor revocation must be one listed in Programme of Requirements Section 7.2 CRL profile;dateis the date of revocation. For production uses this date is the actual date of revocation, however for the G4 TRIAL this date is unbounded.
After modification of the revocations file, create a new CRL by executing:
python generate-crl.py <revocation file>Please do not rename the created CRL file(s) as they are referenced by other certificates (see below) and are used to increment the cRLNumber included within each CRL. Publish the CRL file accordingly (see below).
The Programme of Requirements dictates that CRLs must be renewed (regenerated) at least each 48 hours, and this has been set as default. When publishing the CRL, you may wish to setup a cronjob that automatically recreates the CRL. For testing purposes you may change this setting in config.yaml (see below).
If you'd like to host the CA certificates (as specified in the certificate's authorityInfoAccess extension) and CRLs (as specified in the crlDistributionPoints extension) on your local machine, you can start a minimal webserver:
bash start-server.shIf desired, these files can be hosted using other webservers on other domains (see below).
If you intend to host the certificates and CRLs on another domain modify the config.yaml file by modifing the caIssuersBaseUrl and cRLDistributionPointsBaseUrl parameters. You must recreate all certificates for these values to be used. An example configuration could be:
caIssuersBaseUrl: http://cert.mydomain.com
cRLDistributionPointsBaseUrl: http://crl.mydomain.com
crlRenewalHours: 48
pdsLocation:
url: https://www.github.com/pkioverheid/g4-trial
language: enThe parameter crlRenewalHours indicates the lifespan of a CRL, i.e. the difference between thisUpdate and nextUpdate. The default is 48 hours, but can be modified for testing purposes.
| Filename | Description |
|---|---|
create_ca.py |
Script to create the top level CA private keys and certificates |
create_csr.py |
Script to create a Certificate Signing Request to be signed by another entity |
generate-cert.py |
Script to create any number of end entity private keys and certificates |
generate-crl.py |
Script to create CRLs for a CA |
sign-cert.py |
Signs a certificate based upon a previously generated CSR |
start_server.sh |
A minimal webserver to host generated certificates and CRLs |
ca/private/*.key |
Generated private keys |
ca/certs/*.pem |
Issued certificates |
ca/crl/*.crl |
CRLs for the generated CA certificates |
examples |
Example files to create end entity certificates and revocation lists |
- Python >3.12
These files are provided as-is and no warranty or support is given. However, you may create a Github issue to discuss issues and enhancements.
Based on user input, other G4 hierarchies will be added in future releases.
This project is provided as-is, without any express or implied warranties, including but not limited to merchantability, fitness for a particular purpose, or non-infringement. Use generated self-signed certificate hierarchies is at your own risk, and the maintainers are not responsible for any security issues, misconfigurations, or unintended consequences. External systems, applications and entities must not trust certificates generated by this tooling.