====== Scenario 1.1: Create Root CA with PQ Keys ====== **Category:** [[.:start|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:// [[en:int:pqcrypt:referenz:error_codes_tabelle|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) | ---- ===== Related Scenarios ===== ^ Relationship ^ Scenario ^ Description ^ | **Next Step** | [[.:intermediate_ca_erstellen|1.2 Intermediate CA]] | Sign subordinate CA from Root | | **Then** | [[.:trust_store_konfigurieren|1.4 Trust Store]] | Distribute root certificate | | **Then** | [[.:crl_ocsp_infrastruktur|1.6 CRL/OCSP]] | Set up revocation services | | **Alternative** | [[en:int:pqcrypt:szenarien:schluessel:schluesselpaar_generieren|11.1 Generate Keys]] | Keys only, no certificate | | **Related** | [[en:int:pqcrypt:szenarien:schluessel:schluessel_speichern|11.2 Store Keys]] | More storage options | ---- ===== References ===== === API Documentation === * [[en:int:pqcrypt:api:module:init|Module: init]] * [[en:int:pqcrypt:api:module:keypair|Module: keypair]] * [[en:int:pqcrypt:api:module:dn|Module: dn]] * [[en:int:pqcrypt:api:module:cert|Module: cert]] * [[en:int:pqcrypt:api:module:ext|Module: ext]] * [[en:int:pqcrypt:api:module:free|Module: free]] === Concepts === * [[en:int:pqcrypt:konzepte:fips_204_ml_dsa|ML-DSA (FIPS 204)]] * [[en:int:pqcrypt:konzepte:pki_grundlagen|PKI Fundamentals]] * [[en:int:pqcrypt:konzepte:x509_erweiterungen|X.509 Extensions]] === Security === * [[en:int:pqcrypt:sicherheit:schluessellaengen|Recommended Key Lengths]] * [[en:int:pqcrypt:sicherheit:secure_memory|Secure Memory Management]] === Reference Tables === * [[en:int:pqcrypt:referenz:oid_tabelle|OID Table]] * [[en:int:pqcrypt:referenz:error_codes_tabelle|Error Codes]] * [[en:int:pqcrypt:referenz:schluesselgroessen|Key Sizes]] * [[en:int:pqcrypt:referenz:signaturgroessen|Signature Sizes]] === External Standards === * [[https://csrc.nist.gov/pubs/fips/204/final|NIST FIPS 204: ML-DSA]] * [[https://www.rfc-editor.org/rfc/rfc5280|RFC 5280: X.509 PKI]] * [[https://www.rfc-editor.org/rfc/rfc5958|RFC 5958: PKCS#8]] * [[https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/|IETF: ML-DSA in X.509]] ---- << [[.:start|← PKI Infrastructure]] | [[en:int:pqcrypt:szenarien:start|▲ Scenarios]] | [[.:intermediate_ca_erstellen|1.2 Intermediate CA →]] >> {{tag>scenario pki root-ca ml-dsa-65 self-signed keypair certificate fips-204}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional// ~~NOTOC~~