Scenario 1.1: Create Root CA with PQ Keys

Category: PKI Infrastructure
Complexity: ⭐⭐⭐⭐ (High)
Prerequisites: None (Entry Point)
Estimated Time: 15-30 Minutes


Description

This scenario describes the creation of a self-signed Root CA with Post-Quantum keys. The Root CA forms the Trust Anchor for the entire PKI hierarchy and is the most security-critical element of the infrastructure.

What is created:

  • ML-DSA-65 key pair (Post-Quantum secure)
  • Self-signed X.509 v3 Root certificate
  • Encrypted private key (PKCS#8 with Argon2id)

Use cases:

  • Building a new PQ-capable enterprise PKI
  • Migrating existing PKI to Post-Quantum algorithms
  • Test environment for PQ certificates
  • Isolated PKI for special applications (IoT, code signing)

Flow Diagram

┌─────────────────────────────────────────────────────────────────┐
│                    ROOT CA CREATION                              │
└─────────────────────────────────────────────────────────────────┘

     ┌──────────────┐
     │ 1. Init      │
     │ Library      │
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 2. KeyPair   │ ──────► ML-DSA-65 (FIPS 204)
     │ generate     │         ~4KB Public Key
     └──────┬───────┘         ~2KB Private Key
            │
            ▼
     ┌──────────────┐
     │ 3. DN        │ ──────► CN=WvdS Root CA
     │ create       │         O=DATECpro GmbH
     └──────┬───────┘         C=DE
            │
            ▼
     ┌──────────────┐
     │ 4. Serial    │ ──────► 20 Bytes random (160 bit)
     │ generate     │
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 5. Validity  │ ──────► notBefore: now
     │ set          │         notAfter: +20 years
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 6. Extensions│ ──────► BasicConstraints: CA=true, pathLen=1
     │ set          │         KeyUsage: keyCertSign, cRLSign
     └──────┬───────┘         SKI: SHA-256(publicKey)
            │
            ▼
     ┌──────────────┐
     │ 7. Certificate│ ──────► Subject = Issuer (self-signed)
     │ create       │         Signature with ML-DSA-65
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 8. Export    │ ──────► root-ca.crt.pem (certificate)
     │ PEM          │         root-ca.key.pem (encrypted)
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 9. Cleanup   │ ──────► Release handles
     │              │         Zeroize secrets
     └──────────────┘

Involved Functions

Step FFI Function Rust Crate Description
1 wvds_sec_crypto_x509_init() std::sync Initialize library
2 wvds_sec_crypto_x509_keypair_generate_mldsa(65) ml-dsa ML-DSA-65 key pair
2a wvds_sec_crypto_x509_keypair_self_test() ml-dsa Self-test (sign/verify)
3a wvds_sec_crypto_x509_dn_create() x509-cert Create DN handle
3b wvds_sec_crypto_x509_dn_add_component() x509-cert, der Add CN, O, C
4 wvds_sec_crypto_x509_serial_generate() rand 160-bit serial number
5 wvds_sec_crypto_x509_validity_create() x509-cert Validity period
6a wvds_sec_crypto_x509_ext_set_basic_constraints() x509-cert, der CA=true, pathLen
6b wvds_sec_crypto_x509_ext_set_key_usage() x509-cert, der keyCertSign, cRLSign
6c wvds_sec_crypto_x509_ext_set_ski_from_keypair() sha2 Subject Key Identifier
7 wvds_sec_crypto_x509_cert_create_root() x509-cert, ml-dsa Create root certificate
8a wvds_sec_crypto_x509_cert_to_pem() pem-rfc7468 Certificate as PEM
8b wvds_sec_crypto_x509_keypair_to_pem_encrypted() argon2, aes-gcm Key encrypted
9a wvds_sec_crypto_x509_free_*() std::alloc Release handles
9b wvds_sec_crypto_x509_zeroize_keypair() zeroize Delete secrets

Function Tree

wvds_sec_crypto_x509_init()
│
├── wvds_sec_crypto_x509_keypair_generate_mldsa(level: u8)  → *mut KeyPairHandle
│   │
│   ├── // Parameter selection
│   │   ├── [ML_DSA_44] → ml_dsa::ml_dsa_44::KeyPair::generate(&mut OsRng)
│   │   ├── [ML_DSA_65] → ml_dsa::ml_dsa_65::KeyPair::generate(&mut OsRng)  ✓
│   │   └── [ML_DSA_87] → ml_dsa::ml_dsa_87::KeyPair::generate(&mut OsRng)
│   │
│   ├── // Self-test (FIPS requirement)
│   │   ├── test_msg = [0x00..0x20]  // 32 bytes test data
│   │   ├── signature = signing_key.sign(&test_msg)
│   │   └── assert!(verifying_key.verify(&test_msg, &signature).is_ok())
│   │
│   └── // Create handle
│       └── Box::into_raw(Box::new(KeyPairHandle {
│               algorithm: ML_DSA_65,
│               signing_key,
│               verifying_key
│           }))
│
├── wvds_sec_crypto_x509_dn_create()  → *mut DnHandle
│   └── x509_cert::name::Name::default()
│
├── wvds_sec_crypto_x509_dn_add_component(dn, oid, value)  → i32
│   │
│   ├── [OID_CN = "2.5.4.3"]
│   │   └── dn.0.push(RelativeDistinguishedName::from(
│   │           AttributeTypeAndValue { oid: OID_CN, value: "WvdS Root CA" }
│   │       ))
│   │
│   ├── [OID_O = "2.5.4.10"]
│   │   └── dn.0.push(..., value: "DATECpro GmbH")
│   │
│   └── [OID_C = "2.5.4.6"]
│       └── dn.0.push(..., value: "DE")
│
├── wvds_sec_crypto_x509_serial_generate(out: *mut u8, len: usize)  → i32
│   │
│   ├── // RFC 5280: max 20 bytes, positive
│   │   └── rand::rngs::OsRng.fill_bytes(&mut serial[0..len])
│   │
│   └── // Set highest bit to 0 (positive)
│       └── serial[0] &= 0x7F
│
├── wvds_sec_crypto_x509_validity_create(not_before, not_after)  → *mut ValidityHandle
│   │
│   ├── not_before = x509_cert::time::Time::UtcTime(now)
│   │
│   └── not_after = x509_cert::time::Time::GeneralizedTime(now + 20 years)
│       │
│       └── // GeneralizedTime for dates >= 2050
│
├── wvds_sec_crypto_x509_ext_set_basic_constraints(ext, ca: bool, path_len: i32)  → i32
│   │
│   ├── bc = x509_cert::ext::pkix::BasicConstraints {
│   │       ca: true,
│   │       path_len_constraint: Some(1)  // only 1 intermediate level
│   │   }
│   │
│   └── ext.add(Extension {
│           extn_id: OID_BASIC_CONSTRAINTS,
│           critical: true,  // MUST be critical for CA
│           extn_value: der::Encode::to_der(&bc)
│       })
│
├── wvds_sec_crypto_x509_ext_set_key_usage(ext, flags: u16)  → i32
│   │
│   ├── // For Root CA: keyCertSign (5) + cRLSign (6)
│   │   └── flags = 0x0006  // Bit 5 + Bit 6
│   │
│   ├── ku = x509_cert::ext::pkix::KeyUsage(flags)
│   │
│   └── ext.add(Extension {
│           extn_id: OID_KEY_USAGE,
│           critical: true,  // SHOULD be critical
│           extn_value: der::Encode::to_der(&ku)
│       })
│
├── wvds_sec_crypto_x509_ext_set_ski_from_keypair(ext, keypair)  → i32
│   │
│   ├── // Subject Key Identifier = SHA-256(SubjectPublicKeyInfo.subjectPublicKey)
│   │   ├── public_key_bytes = keypair.verifying_key.to_bytes()
│   │   └── ski = sha2::Sha256::digest(&public_key_bytes)[0..20]
│   │
│   └── ext.add(Extension {
│           extn_id: OID_SUBJECT_KEY_ID,
│           critical: false,
│           extn_value: der::Encode::to_der(&OctetString::new(ski))
│       })
│
├── wvds_sec_crypto_x509_cert_create_root(
│       keypair: *const KeyPairHandle,
│       subject: *const DnHandle,
│       serial: *const u8,
│       serial_len: usize,
│       validity: *const ValidityHandle,
│       extensions: *const ExtHandle
│   )  → *mut CertHandle
│   │
│   ├── // Build TBSCertificate
│   │   └── tbs = x509_cert::TbsCertificate {
│   │           version: Version::V3,
│   │           serial_number: SerialNumber::new(&serial[..serial_len]),
│   │           signature: AlgorithmIdentifier { oid: OID_ML_DSA_65, parameters: None },
│   │           issuer: subject.clone(),      // self-signed: issuer = subject
│   │           validity: validity.clone(),
│   │           subject: subject.clone(),
│   │           subject_public_key_info: keypair.to_spki(),
│   │           extensions: Some(extensions.clone())
│   │       }
│   │
│   ├── // DER-encode TBS certificate
│   │   └── tbs_der = der::Encode::to_der(&tbs)
│   │
│   ├── // Sign with ML-DSA-65
│   │   └── signature = ml_dsa::ml_dsa_65::SigningKey::sign(&tbs_der)
│   │       │
│   │       └── // Deterministic signature (FIPS 204)
│   │           // Signature length: 3293 bytes
│   │
│   └── // Assemble certificate
│       └── cert = x509_cert::Certificate {
│               tbs_certificate: tbs,
│               signature_algorithm: AlgorithmIdentifier { oid: OID_ML_DSA_65 },
│               signature: BitString::from_bytes(&signature)
│           }
│
├── wvds_sec_crypto_x509_cert_to_pem(cert, out, out_len)  → i32
│   │
│   ├── cert_der = der::Encode::to_der(&cert)
│   │
│   └── pem_rfc7468::encode_string("CERTIFICATE", &cert_der)
│       │
│       └── // Example output:
│           // -----BEGIN CERTIFICATE-----
│           // MIIxxxxxx...
│           // -----END CERTIFICATE-----
│
├── wvds_sec_crypto_x509_keypair_to_pem_encrypted(
│       keypair, password, kdf_algorithm, out, out_len
│   )  → i32
│   │
│   ├── // Private key as PKCS#8 DER
│   │   └── private_key_der = keypair.signing_key.to_pkcs8_der()
│   │
│   ├── // Generate salt and nonce
│   │   ├── salt = rand::OsRng.gen::<[u8; 16]>()
│   │   └── nonce = rand::OsRng.gen::<[u8; 12]>()
│   │
│   ├── // Derive Key Encryption Key
│   │   └── [ARGON2ID]
│   │       └── argon2::Argon2::new(
│   │               Algorithm::Argon2id,
│   │               Version::V0x13,
│   │               Params::new(65536, 3, 4, Some(32))  // 64MB, 3 iter, 4 lanes
│   │           ).hash_password_into(password.as_bytes(), &salt, &mut kek)
│   │
│   ├── // Encrypt private key
│   │   └── encrypted = aes_gcm::Aes256Gcm::new(&kek)
│   │           .encrypt(&nonce, private_key_der.as_ref())
│   │
│   ├── // Create EncryptedPrivateKeyInfo (PKCS#8)
│   │   └── epki = pkcs8::EncryptedPrivateKeyInfo {
│   │           encryption_algorithm: ...,
│   │           encrypted_data: encrypted
│   │       }
│   │
│   ├── // Encode as PEM
│   │   └── pem_rfc7468::encode_string("ENCRYPTED PRIVATE KEY", &epki_der)
│   │
│   └── // Zeroize KEK
│       └── zeroize::Zeroize::zeroize(&mut kek)
│
└── // Cleanup
    │
    ├── wvds_sec_crypto_x509_free_cert(cert)
    ├── wvds_sec_crypto_x509_free_keypair(keypair)
    │   └── // Automatic zeroize via Drop
    ├── wvds_sec_crypto_x509_free_dn(dn)
    ├── wvds_sec_crypto_x509_free_validity(validity)
    ├── wvds_sec_crypto_x509_free_ext(ext)
    └── wvds_sec_crypto_x509_shutdown()

Code Examples

C# (.NET Wrapper)

using System;
using System.IO;
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
namespace RootCaExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Password for private key (in production: enter securely!)
            string keyPassword = "MyStr0ng!RootCA#Password2024";
 
            // 1. Initialize context
            using var context = PqCryptoContext.Initialize();
 
            // 2. Generate ML-DSA-65 key pair
            Console.WriteLine("Generating ML-DSA-65 key pair...");
            using var keyPair = context.GenerateKeyPair(PqAlgorithm.MlDsa65);
 
            // Perform self-test
            if (!keyPair.SelfTest())
                throw new CryptographicException("KeyPair self-test failed!");
 
            Console.WriteLine($"  Public Key:  {keyPair.PublicKeySize} Bytes");
            Console.WriteLine($"  Private Key: {keyPair.PrivateKeySize} Bytes");
 
            // 3. Create Distinguished Name
            var subjectDn = new DistinguishedNameBuilder()
                .AddCommonName("WvdS Root CA")
                .AddOrganization("DATECpro GmbH")
                .AddOrganizationalUnit("PQ-Security")
                .AddCountry("DE")
                .AddLocality("Munich")
                .Build();
 
            Console.WriteLine($"Subject DN: {subjectDn}");
 
            // 4. Validity period (20 years for Root CA)
            var validity = new CertificateValidity(
                notBefore: DateTime.UtcNow,
                notAfter: DateTime.UtcNow.AddYears(20)
            );
 
            // 5. Extensions for Root CA
            var extensions = new X509ExtensionsBuilder()
                // BasicConstraints: CA=true, max 1 intermediate level
                .AddBasicConstraints(isCa: true, pathLengthConstraint: 1, critical: true)
                // KeyUsage: only certificate and CRL signing
                .AddKeyUsage(
                    KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign,
                    critical: true
                )
                // Subject Key Identifier for later AKI reference
                .AddSubjectKeyIdentifier(keyPair)
                .Build();
 
            // 6. Create root certificate (self-signed)
            Console.WriteLine("Creating self-signed root certificate...");
            using var rootCert = context.CreateRootCertificate(
                keyPair: keyPair,
                subject: subjectDn,
                validity: validity,
                extensions: extensions
            );
 
            // 7. Output certificate information
            Console.WriteLine("\n=== ROOT CA CERTIFICATE ===");
            Console.WriteLine($"Subject:        {rootCert.Subject}");
            Console.WriteLine($"Issuer:         {rootCert.Issuer}");
            Console.WriteLine($"Serial:         {rootCert.SerialNumber}");
            Console.WriteLine($"Not Before:     {rootCert.NotBefore:yyyy-MM-dd HH:mm:ss} UTC");
            Console.WriteLine($"Not After:      {rootCert.NotAfter:yyyy-MM-dd HH:mm:ss} UTC");
            Console.WriteLine($"Algorithm:      {rootCert.SignatureAlgorithm}");
            Console.WriteLine($"Thumbprint:     {rootCert.Thumbprint}");
            Console.WriteLine($"Is CA:          {rootCert.IsCertificateAuthority}");
            Console.WriteLine($"Path Length:    {rootCert.PathLengthConstraint}");
 
            // 8. Save as PEM files
            string certPath = "root-ca.crt.pem";
            string keyPath = "root-ca.key.pem";
 
            // Certificate (public)
            File.WriteAllText(certPath, rootCert.ExportToPem());
            Console.WriteLine($"\nCertificate saved: {certPath}");
 
            // Private key (encrypted with Argon2id)
            File.WriteAllText(keyPath, keyPair.ExportToEncryptedPem(
                password: keyPassword,
                kdfAlgorithm: KeyDerivationAlgorithm.Argon2id
            ));
            Console.WriteLine($"Private key saved: {keyPath} (encrypted)");
 
            // 9. Validation: reload certificate and verify
            Console.WriteLine("\n=== VALIDATION ===");
            using var loadedCert = context.LoadCertificateFromPem(File.ReadAllText(certPath));
            using var loadedKey = context.LoadKeyPairFromEncryptedPem(
                File.ReadAllText(keyPath),
                keyPassword
            );
 
            // Verify self-signature
            bool signatureValid = loadedCert.VerifySignature(loadedCert);  // self-signed
            Console.WriteLine($"Self-signature valid: {signatureValid}");
 
            // Verify key pair match
            bool keyMatch = loadedCert.PublicKeyMatches(loadedKey);
            Console.WriteLine($"Public key match:     {keyMatch}");
 
            Console.WriteLine("\n✓ Root CA successfully created!");
        }
    }
}

Delphi (FFI)

program CreateRootCA;
 
{$APPTYPE CONSOLE}
 
uses
  SysUtils, DateUtils,
  WvdS.PqCrypto.FFI;  // FFI unit with declarations
 
const
  KEY_PASSWORD = 'MyStr0ng!RootCA#Password2024';
 
var
  res: Integer;
  keypair: Pointer;
  dn: Pointer;
  validity: Pointer;
  ext: Pointer;
  cert: Pointer;
  serial: array[0..19] of Byte;
  pem_buf: array[0..65535] of AnsiChar;
  pem_len: NativeUInt;
 
begin
  WriteLn('=== WvdS Root CA Creation ===');
  WriteLn;
 
  // 1. Initialize library
  res := wvds_sec_crypto_x509_init();
  if res <> WVDS_OK then
  begin
    WriteLn('ERROR: Init failed (', res, ')');
    Exit;
  end;
 
  try
    // 2. Generate ML-DSA-65 key pair
    WriteLn('Generating ML-DSA-65 key pair...');
    keypair := wvds_sec_crypto_x509_keypair_generate_mldsa(65);
    if keypair = nil then
      raise Exception.Create('KeyPair generation failed');
 
    // Self-test
    res := wvds_sec_crypto_x509_keypair_self_test(keypair);
    if res <> WVDS_OK then
      raise Exception.Create('KeyPair self-test failed');
    WriteLn('  Self-test: OK');
 
    // 3. Create Distinguished Name
    WriteLn('Creating Distinguished Name...');
    dn := wvds_sec_crypto_x509_dn_create();
    if dn = nil then
      raise Exception.Create('DN creation failed');
 
    wvds_sec_crypto_x509_dn_add_component(dn, PAnsiChar('2.5.4.3'),  PAnsiChar('WvdS Root CA'));      // CN
    wvds_sec_crypto_x509_dn_add_component(dn, PAnsiChar('2.5.4.10'), PAnsiChar('DATECpro GmbH'));    // O
    wvds_sec_crypto_x509_dn_add_component(dn, PAnsiChar('2.5.4.11'), PAnsiChar('PQ-Security'));      // OU
    wvds_sec_crypto_x509_dn_add_component(dn, PAnsiChar('2.5.4.6'),  PAnsiChar('DE'));               // C
 
    // 4. Generate serial number (20 bytes = 160 bit)
    WriteLn('Generating serial number...');
    res := wvds_sec_crypto_x509_serial_generate(@serial[0], 20);
    if res <> WVDS_OK then
      raise Exception.Create('Serial generation failed');
 
    // 5. Validity: 20 years
    WriteLn('Setting validity period (20 years)...');
    validity := wvds_sec_crypto_x509_validity_create(
      DateTimeToUnix(Now, False),                      // not_before: now
      DateTimeToUnix(IncYear(Now, 20), False)          // not_after: +20 years
    );
    if validity = nil then
      raise Exception.Create('Validity creation failed');
 
    // 6. Create extensions
    WriteLn('Setting extensions...');
    ext := wvds_sec_crypto_x509_ext_create();
    if ext = nil then
      raise Exception.Create('Extension creation failed');
 
    // BasicConstraints: CA=true, pathLen=1
    res := wvds_sec_crypto_x509_ext_set_basic_constraints(ext, True, 1);
    if res <> WVDS_OK then
      raise Exception.Create('BasicConstraints failed');
 
    // KeyUsage: keyCertSign (Bit 5) + cRLSign (Bit 6) = 0x0006
    res := wvds_sec_crypto_x509_ext_set_key_usage(ext, $0006);
    if res <> WVDS_OK then
      raise Exception.Create('KeyUsage failed');
 
    // Subject Key Identifier
    res := wvds_sec_crypto_x509_ext_set_ski_from_keypair(ext, keypair);
    if res <> WVDS_OK then
      raise Exception.Create('SKI failed');
 
    // 7. Create root certificate (self-signed)
    WriteLn('Creating self-signed root certificate...');
    cert := wvds_sec_crypto_x509_cert_create_root(
      keypair,          // Key pair
      dn,               // Subject (= Issuer for Root)
      @serial[0], 20,   // Serial number
      validity,         // Validity
      ext               // Extensions
    );
    if cert = nil then
      raise Exception.Create('Certificate creation failed');
 
    // 8. Save as PEM
    WriteLn;
    WriteLn('Saving files...');
 
    // Certificate
    pem_len := SizeOf(pem_buf);
    res := wvds_sec_crypto_x509_cert_to_pem(cert, @pem_buf[0], @pem_len);
    if res <> WVDS_OK then
      raise Exception.Create('Certificate export failed');
 
    with TFileStream.Create('root-ca.crt.pem', fmCreate) do
    try
      Write(pem_buf[0], pem_len);
    finally
      Free;
    end;
    WriteLn('  root-ca.crt.pem saved');
 
    // Private key (encrypted)
    pem_len := SizeOf(pem_buf);
    res := wvds_sec_crypto_x509_keypair_to_pem_encrypted(
      keypair,
      PAnsiChar(KEY_PASSWORD),
      WVDS_KDF_ARGON2ID,
      @pem_buf[0],
      @pem_len
    );
    if res <> WVDS_OK then
      raise Exception.Create('Key export failed');
 
    with TFileStream.Create('root-ca.key.pem', fmCreate) do
    try
      Write(pem_buf[0], pem_len);
    finally
      Free;
    end;
    WriteLn('  root-ca.key.pem saved (encrypted)');
 
    WriteLn;
    WriteLn('=== Root CA successfully created! ===');
 
  finally
    // 9. Cleanup
    if cert <> nil then wvds_sec_crypto_x509_free_cert(cert);
    if keypair <> nil then wvds_sec_crypto_x509_free_keypair(keypair);
    if dn <> nil then wvds_sec_crypto_x509_free_dn(dn);
    if validity <> nil then wvds_sec_crypto_x509_free_validity(validity);
    if ext <> nil then wvds_sec_crypto_x509_free_ext(ext);
    wvds_sec_crypto_x509_shutdown();
  end;
end.

Parameters

wvds_sec_crypto_x509_keypair_generate_mldsa

Parameter Type Description Valid Values
level u8 ML-DSA Security Level 44, 65, 87
Level NIST Security Public Key Private Key Signature
44 Level 2 (~128-bit) 1,312 Bytes 2,560 Bytes 2,420 Bytes
65 Level 3 (~192-bit) 1,952 Bytes 4,032 Bytes 3,293 Bytes
87 Level 5 (~256-bit) 2,592 Bytes 4,896 Bytes 4,595 Bytes

wvds_sec_crypto_x509_dn_add_component

Parameter Type Description Example
dn *mut DnHandle DN handle
oid *const c_char OID as string „2.5.4.3“
value *const c_char UTF-8 value „WvdS Root CA“
OID Constant Description Example Value
2.5.4.3 OID_CN Common Name WvdS Root CA
2.5.4.10 OID_O Organization DATECpro GmbH
2.5.4.11 OID_OU Organizational Unit PQ-Security
2.5.4.6 OID_C Country (2 characters) DE
2.5.4.8 OID_ST State/Province Bavaria
2.5.4.7 OID_L Locality Munich

wvds_sec_crypto_x509_ext_set_basic_constraints

Parameter Type Description Root CA Value
ext *mut ExtHandle Extension handle
ca bool Is CA certificate true
path_len i32 Max path length (-1 = unlimited) 1 or 2

wvds_sec_crypto_x509_ext_set_key_usage

Flag Bit Value Description
digitalSignature 0 0x0080 Digital signatures
nonRepudiation 1 0x0040 Non-repudiation
keyEncipherment 2 0x0020 Key encipherment
dataEncipherment 3 0x0010 Data encipherment
keyAgreement 4 0x0008 Key agreement
keyCertSign 5 0x0004 Certificate signing
cRLSign 6 0x0002 CRL signing
encipherOnly 7 0x0001 Encipher only

For Root CA: flags = 0x0006 (keyCertSign + cRLSign)


Return Values

Code Constant Meaning
0 WVDS_OK Success
1 WVDS_ERROR_INVALID_PARAMETER Invalid parameter (e.g., level ≠ 44/65/87)
2 WVDS_ERROR_OUT_OF_MEMORY Memory allocation failed
3 WVDS_ERROR_NOT_INITIALIZED init() not called
200 WVDS_ERROR_KEY_GENERATION_FAILED Key generation failed
201 WVDS_ERROR_SIGNATURE_FAILED Signing failed
210 WVDS_ERROR_KEYPAIR_SELF_TEST_FAILED Self-test failed

Complete list: Error Codes


Output Files

root-ca.crt.pem

-----BEGIN CERTIFICATE-----
MIIHxjCCBiagAwIBAgIUP7J2kM9x... (Base64-encoded DER)
...
-----END CERTIFICATE-----
Field Value
Version 3 (0x02)
Serial 20 bytes random
Signature Algorithm ML-DSA-65 (OID: 2.16.840.1.101.3.4.3.18)
Issuer CN=WvdS Root CA, O=DATECpro GmbH, C=DE
Subject CN=WvdS Root CA, O=DATECpro GmbH, C=DE
Validity 20 years
Public Key ML-DSA-65 (~1,952 bytes)
Extensions BasicConstraints, KeyUsage, SKI
Signature ML-DSA-65 (~3,293 bytes)

root-ca.key.pem

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIHbTBXBgkqhkiG9w0BBQ0w... (PKCS#8 EncryptedPrivateKeyInfo)
...
-----END ENCRYPTED PRIVATE KEY-----
Field Value
Format PKCS#8 EncryptedPrivateKeyInfo
KDF Argon2id (64MB, 3 iterations, 4 lanes)
Cipher AES-256-GCM
Key Size ~4,032 bytes (ML-DSA-65 private key)

Security Notes

CRITICAL – Root CA Private Key:

The Root CA private key is the most security-critical element of the entire PKI. Compromise means complete loss of trust!

  • Never generate or store on networked systems
  • Never store unencrypted
  • Never transmit via email or insecure channels

Recommended Protection Measures:

  • Air-gapped system: Root CA operations on isolated computer without network
  • HSM: Hardware Security Module for key storage (e.g., YubiHSM, Thales Luna)
  • Encryption: At least AES-256 with strong password (>=20 characters)
  • Physical security: Encrypted USB stick in safe or bank vault
  • Backup: At least 2 copies at separate locations
  • Key ceremony: Documented process with witnesses for all Root CA operations
  • Audit log: Log all access

Best Practices:

  • ML-DSA-65 offers good ratio of security and performance for Root CAs
  • pathLength=1 limits hierarchy to Root → Intermediate → End-Entity
  • 20 years validity is common for Root CAs (max 25 years recommended)
  • Set SKI enables later AKI reference in intermediate certificates
  • Self-test after generation ensures correct implementation

Common Errors

Problem Cause Solution
KEY_GENERATION_FAILED Not enough entropy Check OS random source, /dev/urandom available?
KEYPAIR_SELF_TEST_FAILED Defective implementation Check library version, recompile
Certificate invalid DN empty Set at least CN
Key not readable Wrong password Check password, encoding (UTF-8)
pathLength error Value < -1 -1 for unlimited, 0, 1, 2, … for limit
NOT_INITIALIZED init() forgotten Call wvds_sec_crypto_x509_init() first
Memory leak Handles not released Call all free_*() functions
PEM too large Buffer too small Query size first (out_len = 0)

Relationship Scenario Description
Next Step 1.2 Intermediate CA Sign subordinate CA from Root
Then 1.4 Trust Store Distribute root certificate
Then 1.6 CRL/OCSP Set up revocation services
Alternative 11.1 Generate Keys Keys only, no certificate
Related 11.2 Store Keys More storage options

References

API Documentation

Concepts

Security

Reference Tables

External Standards

Zuletzt geändert: on 2026/01/30 at 06:34 AM