====== Szenario 1.1: Root-CA mit PQ-Schlüsseln erstellen ======
**Kategorie:** [[.:start|PKI-Infrastruktur]] \\
**Komplexität:** ⭐⭐⭐⭐ (Hoch) \\
**Voraussetzungen:** Keine (Einstiegspunkt) \\
**Geschätzte Zeit:** 15-30 Minuten
----
===== Beschreibung =====
Dieses Szenario beschreibt die Erstellung einer **selbstsignierten Root-CA** mit Post-Quantum-Schlüsseln. Die Root-CA bildet den **Vertrauensanker (Trust Anchor)** für die gesamte PKI-Hierarchie und ist das sicherheitskritischste Element der Infrastruktur.
**Was wird erstellt:**
* ML-DSA-65 Schlüsselpaar (Post-Quantum-sicher)
* Selbstsigniertes X.509 v3 Root-Zertifikat
* Verschlüsselter Private Key (PKCS#8 mit Argon2id)
**Anwendungsfälle:**
* Aufbau einer neuen PQ-fähigen Enterprise-PKI
* Migration bestehender PKI zu Post-Quantum-Algorithmen
* Testumgebung für PQ-Zertifikate
* Isolierte PKI für spezielle Anwendungen (IoT, Code-Signing)
----
===== Ablaufdiagramm =====
┌─────────────────────────────────────────────────────────────────┐
│ ROOT-CA ERSTELLUNG │
└─────────────────────────────────────────────────────────────────┘
┌──────────────┐
│ 1. Init │
│ Bibliothek │
└──────┬───────┘
│
▼
┌──────────────┐
│ 2. KeyPair │ ──────► ML-DSA-65 (FIPS 204)
│ generieren │ ~4KB Public Key
└──────┬───────┘ ~2KB Private Key
│
▼
┌──────────────┐
│ 3. DN │ ──────► CN=WvdS Root CA
│ erstellen │ O=DATECpro GmbH
└──────┬───────┘ C=DE
│
▼
┌──────────────┐
│ 4. Serial │ ──────► 20 Bytes Zufall (160 bit)
│ generieren │
└──────┬───────┘
│
▼
┌──────────────┐
│ 5. Validity │ ──────► notBefore: jetzt
│ festlegen │ notAfter: +20 Jahre
└──────┬───────┘
│
▼
┌──────────────┐
│ 6. Extensions│ ──────► BasicConstraints: CA=true, pathLen=1
│ setzen │ KeyUsage: keyCertSign, cRLSign
└──────┬───────┘ SKI: SHA-256(publicKey)
│
▼
┌──────────────┐
│ 7. Zertifikat│ ──────► Subject = Issuer (selbstsigniert)
│ erstellen │ Signatur mit ML-DSA-65
└──────┬───────┘
│
▼
┌──────────────┐
│ 8. Export │ ──────► root-ca.crt.pem (Zertifikat)
│ PEM │ root-ca.key.pem (verschlüsselt)
└──────┬───────┘
│
▼
┌──────────────┐
│ 9. Cleanup │ ──────► Handles freigeben
│ │ Secrets zeroizen
└──────────────┘
----
===== Beteiligte Funktionen =====
^ Schritt ^ FFI-Funktion ^ Rust-Crate ^ Beschreibung ^
| 1 | ''wvds_sec_crypto_x509_init()'' | ''std::sync'' | Bibliothek initialisieren |
| 2 | ''wvds_sec_crypto_x509_keypair_generate_mldsa(65)'' | ''ml-dsa'' | ML-DSA-65 Schlüsselpaar |
| 2a | ''wvds_sec_crypto_x509_keypair_self_test()'' | ''ml-dsa'' | Selbsttest (sign/verify) |
| 3a | ''wvds_sec_crypto_x509_dn_create()'' | ''x509-cert'' | DN-Handle erstellen |
| 3b | ''wvds_sec_crypto_x509_dn_add_component()'' | ''x509-cert'', ''der'' | CN, O, C hinzufügen |
| 4 | ''wvds_sec_crypto_x509_serial_generate()'' | ''rand'' | 160-bit Seriennummer |
| 5 | ''wvds_sec_crypto_x509_validity_create()'' | ''x509-cert'' | Gültigkeitszeitraum |
| 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'' | Root-Zertifikat erstellen |
| 8a | ''wvds_sec_crypto_x509_cert_to_pem()'' | ''pem-rfc7468'' | Zertifikat als PEM |
| 8b | ''wvds_sec_crypto_x509_keypair_to_pem_encrypted()'' | ''argon2'', ''aes-gcm'' | Key verschlüsselt |
| 9a | ''wvds_sec_crypto_x509_free_*()'' | ''std::alloc'' | Handles freigeben |
| 9b | ''wvds_sec_crypto_x509_zeroize_keypair()'' | ''zeroize'' | Secrets löschen |
----
===== Funktionsbaum =====
wvds_sec_crypto_x509_init()
│
├── wvds_sec_crypto_x509_keypair_generate_mldsa(level: u8) → *mut KeyPairHandle
│ │
│ ├── // Parameterwahl
│ │ ├── [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)
│ │
│ ├── // Selbsttest (FIPS-Anforderung)
│ │ ├── test_msg = [0x00..0x20] // 32 Bytes Testdaten
│ │ ├── signature = signing_key.sign(&test_msg)
│ │ └── assert!(verifying_key.verify(&test_msg, &signature).is_ok())
│ │
│ └── // Handle erstellen
│ └── 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, positiv
│ │ └── rand::rngs::OsRng.fill_bytes(&mut serial[0..len])
│ │
│ └── // Höchstes Bit auf 0 setzen (positiv)
│ └── 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 für Daten >= 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) // nur 1 Intermediate-Ebene
│ │ }
│ │
│ └── ext.add(Extension {
│ extn_id: OID_BASIC_CONSTRAINTS,
│ critical: true, // MUSS critical sein für CA
│ extn_value: der::Encode::to_der(&bc)
│ })
│
├── wvds_sec_crypto_x509_ext_set_key_usage(ext, flags: u16) → i32
│ │
│ ├── // Für 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, // SOLLTE critical sein
│ 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
│ │
│ ├── // TBSCertificate aufbauen
│ │ └── 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(), // selbstsigniert: issuer = subject
│ │ validity: validity.clone(),
│ │ subject: subject.clone(),
│ │ subject_public_key_info: keypair.to_spki(),
│ │ extensions: Some(extensions.clone())
│ │ }
│ │
│ ├── // TBS-Certificate DER-encodieren
│ │ └── tbs_der = der::Encode::to_der(&tbs)
│ │
│ ├── // Signieren mit ML-DSA-65
│ │ └── signature = ml_dsa::ml_dsa_65::SigningKey::sign(&tbs_der)
│ │ │
│ │ └── // Deterministische Signatur (FIPS 204)
│ │ // Signaturlänge: 3293 Bytes
│ │
│ └── // Certificate zusammenbauen
│ └── 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)
│ │
│ └── // Beispiel-Output:
│ // -----BEGIN CERTIFICATE-----
│ // MIIxxxxxx...
│ // -----END CERTIFICATE-----
│
├── wvds_sec_crypto_x509_keypair_to_pem_encrypted(
│ keypair, password, kdf_algorithm, out, out_len
│ ) → i32
│ │
│ ├── // Private Key als PKCS#8 DER
│ │ └── private_key_der = keypair.signing_key.to_pkcs8_der()
│ │
│ ├── // Salt und Nonce generieren
│ │ ├── salt = rand::OsRng.gen::<[u8; 16]>()
│ │ └── nonce = rand::OsRng.gen::<[u8; 12]>()
│ │
│ ├── // Key Encryption Key ableiten
│ │ └── [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)
│ │
│ ├── // Private Key verschlüsseln
│ │ └── encrypted = aes_gcm::Aes256Gcm::new(&kek)
│ │ .encrypt(&nonce, private_key_der.as_ref())
│ │
│ ├── // EncryptedPrivateKeyInfo erstellen (PKCS#8)
│ │ └── epki = pkcs8::EncryptedPrivateKeyInfo {
│ │ encryption_algorithm: ...,
│ │ encrypted_data: encrypted
│ │ }
│ │
│ ├── // Als PEM encodieren
│ │ └── pem_rfc7468::encode_string("ENCRYPTED PRIVATE KEY", &epki_der)
│ │
│ └── // KEK zeroizen
│ └── zeroize::Zeroize::zeroize(&mut kek)
│
└── // Cleanup
│
├── wvds_sec_crypto_x509_free_cert(cert)
├── wvds_sec_crypto_x509_free_keypair(keypair)
│ └── // Automatisches 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-Beispiele =====
=== C# (.NET Wrapper) ===
using System;
using System.IO;
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
namespace RootCaExample
{
class Program
{
static void Main(string[] args)
{
// Passwort für Private Key (in Produktion: sicher eingeben!)
string keyPassword = "MyStr0ng!RootCA#Password2024";
// 1. Kontext initialisieren
using var context = PqCryptoContext.Initialize();
// 2. ML-DSA-65 Schlüsselpaar generieren
Console.WriteLine("Generiere ML-DSA-65 Schlüsselpaar...");
using var keyPair = context.GenerateKeyPair(PqAlgorithm.MlDsa65);
// Selbsttest durchführen
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. Distinguished Name erstellen
var subjectDn = new DistinguishedNameBuilder()
.AddCommonName("WvdS Root CA")
.AddOrganization("DATECpro GmbH")
.AddOrganizationalUnit("PQ-Security")
.AddCountry("DE")
.AddLocality("München")
.Build();
Console.WriteLine($"Subject DN: {subjectDn}");
// 4. Gültigkeitszeitraum (20 Jahre für Root-CA)
var validity = new CertificateValidity(
notBefore: DateTime.UtcNow,
notAfter: DateTime.UtcNow.AddYears(20)
);
// 5. Extensions für Root-CA
var extensions = new X509ExtensionsBuilder()
// BasicConstraints: CA=true, max 1 Intermediate-Ebene
.AddBasicConstraints(isCa: true, pathLengthConstraint: 1, critical: true)
// KeyUsage: nur Zertifikat- und CRL-Signierung
.AddKeyUsage(
KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign,
critical: true
)
// Subject Key Identifier für spätere AKI-Referenzierung
.AddSubjectKeyIdentifier(keyPair)
.Build();
// 6. Root-Zertifikat erstellen (selbstsigniert)
Console.WriteLine("Erstelle selbstsigniertes Root-Zertifikat...");
using var rootCert = context.CreateRootCertificate(
keyPair: keyPair,
subject: subjectDn,
validity: validity,
extensions: extensions
);
// 7. Zertifikat-Informationen ausgeben
Console.WriteLine("\n=== ROOT-CA ZERTIFIKAT ===");
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. Als PEM-Dateien speichern
string certPath = "root-ca.crt.pem";
string keyPath = "root-ca.key.pem";
// Zertifikat (öffentlich)
File.WriteAllText(certPath, rootCert.ExportToPem());
Console.WriteLine($"\nZertifikat gespeichert: {certPath}");
// Private Key (verschlüsselt mit Argon2id)
File.WriteAllText(keyPath, keyPair.ExportToEncryptedPem(
password: keyPassword,
kdfAlgorithm: KeyDerivationAlgorithm.Argon2id
));
Console.WriteLine($"Private Key gespeichert: {keyPath} (verschlüsselt)");
// 9. Validierung: Zertifikat neu laden und prüfen
Console.WriteLine("\n=== VALIDIERUNG ===");
using var loadedCert = context.LoadCertificateFromPem(File.ReadAllText(certPath));
using var loadedKey = context.LoadKeyPairFromEncryptedPem(
File.ReadAllText(keyPath),
keyPassword
);
// Selbstsignatur verifizieren
bool signatureValid = loadedCert.VerifySignature(loadedCert); // self-signed
Console.WriteLine($"Selbstsignatur gültig: {signatureValid}");
// Key-Paar-Zugehörigkeit prüfen
bool keyMatch = loadedCert.PublicKeyMatches(loadedKey);
Console.WriteLine($"Public Key Match: {keyMatch}");
Console.WriteLine("\n✓ Root-CA erfolgreich erstellt!");
}
}
}
=== Delphi (FFI) ===
program CreateRootCA;
{$APPTYPE CONSOLE}
uses
SysUtils, DateUtils,
WvdS.PqCrypto.FFI; // FFI-Unit mit Deklarationen
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 Erstellung ===');
WriteLn;
// 1. Bibliothek initialisieren
res := wvds_sec_crypto_x509_init();
if res <> WVDS_OK then
begin
WriteLn('FEHLER: Init fehlgeschlagen (', res, ')');
Exit;
end;
try
// 2. ML-DSA-65 Schlüsselpaar generieren
WriteLn('Generiere ML-DSA-65 Schlüsselpaar...');
keypair := wvds_sec_crypto_x509_keypair_generate_mldsa(65);
if keypair = nil then
raise Exception.Create('KeyPair-Generierung fehlgeschlagen');
// Selbsttest
res := wvds_sec_crypto_x509_keypair_self_test(keypair);
if res <> WVDS_OK then
raise Exception.Create('KeyPair-Selbsttest fehlgeschlagen');
WriteLn(' Selbsttest: OK');
// 3. Distinguished Name erstellen
WriteLn('Erstelle Distinguished Name...');
dn := wvds_sec_crypto_x509_dn_create();
if dn = nil then
raise Exception.Create('DN-Erstellung fehlgeschlagen');
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. Seriennummer generieren (20 Bytes = 160 Bit)
WriteLn('Generiere Seriennummer...');
res := wvds_sec_crypto_x509_serial_generate(@serial[0], 20);
if res <> WVDS_OK then
raise Exception.Create('Serial-Generierung fehlgeschlagen');
// 5. Gültigkeit: 20 Jahre
WriteLn('Setze Gültigkeitszeitraum (20 Jahre)...');
validity := wvds_sec_crypto_x509_validity_create(
DateTimeToUnix(Now, False), // not_before: jetzt
DateTimeToUnix(IncYear(Now, 20), False) // not_after: +20 Jahre
);
if validity = nil then
raise Exception.Create('Validity-Erstellung fehlgeschlagen');
// 6. Extensions erstellen
WriteLn('Setze Extensions...');
ext := wvds_sec_crypto_x509_ext_create();
if ext = nil then
raise Exception.Create('Extension-Erstellung fehlgeschlagen');
// 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 fehlgeschlagen');
// 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 fehlgeschlagen');
// Subject Key Identifier
res := wvds_sec_crypto_x509_ext_set_ski_from_keypair(ext, keypair);
if res <> WVDS_OK then
raise Exception.Create('SKI fehlgeschlagen');
// 7. Root-Zertifikat erstellen (selbstsigniert)
WriteLn('Erstelle selbstsigniertes Root-Zertifikat...');
cert := wvds_sec_crypto_x509_cert_create_root(
keypair, // Schlüsselpaar
dn, // Subject (= Issuer bei Root)
@serial[0], 20, // Seriennummer
validity, // Gültigkeit
ext // Extensions
);
if cert = nil then
raise Exception.Create('Zertifikat-Erstellung fehlgeschlagen');
// 8. Als PEM speichern
WriteLn;
WriteLn('Speichere Dateien...');
// Zertifikat
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('Zertifikat-Export fehlgeschlagen');
with TFileStream.Create('root-ca.crt.pem', fmCreate) do
try
Write(pem_buf[0], pem_len);
finally
Free;
end;
WriteLn(' root-ca.crt.pem gespeichert');
// Private Key (verschlüsselt)
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 fehlgeschlagen');
with TFileStream.Create('root-ca.key.pem', fmCreate) do
try
Write(pem_buf[0], pem_len);
finally
Free;
end;
WriteLn(' root-ca.key.pem gespeichert (verschlüsselt)');
WriteLn;
WriteLn('=== Root-CA erfolgreich erstellt! ===');
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.
----
===== Parameter =====
==== wvds_sec_crypto_x509_keypair_generate_mldsa ====
^ Parameter ^ Typ ^ Beschreibung ^ Gültige Werte ^
| ''level'' | ''u8'' | ML-DSA Security Level | ''44'', ''65'', ''87'' |
^ Level ^ NIST-Sicherheit ^ Public Key ^ Private Key ^ Signatur ^
| 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 ^ Typ ^ Beschreibung ^ Beispiel ^
| ''dn'' | ''*mut DnHandle'' | DN-Handle | – |
| ''oid'' | ''*const c_char'' | OID als String | ''"2.5.4.3"'' |
| ''value'' | ''*const c_char'' | UTF-8 Wert | ''"WvdS Root CA"'' |
^ OID ^ Konstante ^ Beschreibung ^ Beispielwert ^
| 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 Zeichen) | ''DE'' |
| 2.5.4.8 | OID_ST | State/Province | ''Bayern'' |
| 2.5.4.7 | OID_L | Locality | ''München'' |
==== wvds_sec_crypto_x509_ext_set_basic_constraints ====
^ Parameter ^ Typ ^ Beschreibung ^ Root-CA Wert ^
| ''ext'' | ''*mut ExtHandle'' | Extension-Handle | – |
| ''ca'' | ''bool'' | Ist CA-Zertifikat | ''true'' |
| ''path_len'' | ''i32'' | Max. Pfadlänge (-1 = unbegrenzt) | ''1'' oder ''2'' |
==== wvds_sec_crypto_x509_ext_set_key_usage ====
^ Flag ^ Bit ^ Wert ^ Beschreibung ^
| digitalSignature | 0 | 0x0080 | Digitale Signaturen |
| nonRepudiation | 1 | 0x0040 | Nichtabstreitbarkeit |
| keyEncipherment | 2 | 0x0020 | Schlüsselverschlüsselung |
| dataEncipherment | 3 | 0x0010 | Datenverschlüsselung |
| keyAgreement | 4 | 0x0008 | Schlüsselvereinbarung |
| **keyCertSign** | 5 | 0x0004 | **Zertifikat-Signierung** ✓ |
| **cRLSign** | 6 | 0x0002 | **CRL-Signierung** ✓ |
| encipherOnly | 7 | 0x0001 | Nur Verschlüsselung |
**Für Root-CA:** ''flags = 0x0006'' (keyCertSign + cRLSign)
----
===== Rückgabewerte =====
^ Code ^ Konstante ^ Bedeutung ^
| 0 | ''WVDS_OK'' | Erfolg |
| 1 | ''WVDS_ERROR_INVALID_PARAMETER'' | Ungültiger Parameter (z.B. level ≠ 44/65/87) |
| 2 | ''WVDS_ERROR_OUT_OF_MEMORY'' | Speicherallokation fehlgeschlagen |
| 3 | ''WVDS_ERROR_NOT_INITIALIZED'' | ''init()'' nicht aufgerufen |
| 200 | ''WVDS_ERROR_KEY_GENERATION_FAILED'' | Schlüsselgenerierung fehlgeschlagen |
| 201 | ''WVDS_ERROR_SIGNATURE_FAILED'' | Signierung fehlgeschlagen |
| 210 | ''WVDS_ERROR_KEYPAIR_SELF_TEST_FAILED'' | Selbsttest fehlgeschlagen |
→ //Vollständige Liste:// [[de:int:pqcrypt:referenz:error_codes_tabelle|Error Codes]]
----
===== Ausgabe-Dateien =====
==== root-ca.crt.pem ====
-----BEGIN CERTIFICATE-----
MIIHxjCCBiagAwIBAgIUP7J2kM9x... (Base64-encoded DER)
...
-----END CERTIFICATE-----
^ Feld ^ Wert ^
| Version | 3 (0x02) |
| Serial | 20 Bytes Zufall |
| 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 Jahre |
| 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-----
^ Feld ^ Wert ^
| Format | PKCS#8 EncryptedPrivateKeyInfo |
| KDF | Argon2id (64MB, 3 Iterationen, 4 Lanes) |
| Cipher | AES-256-GCM |
| Key Size | ~4.032 Bytes (ML-DSA-65 Private Key) |
----
===== Sicherheitshinweise =====
**KRITISCH – Root-CA Private Key:**
Der Private Key der Root-CA ist das **sicherheitskritischste Element** der gesamten PKI. Kompromittierung bedeutet vollständigen Vertrauensverlust!
* **Niemals** auf vernetzten Systemen generieren oder speichern
* **Niemals** unverschlüsselt speichern
* **Niemals** per E-Mail oder unsichere Kanäle übertragen
**Empfohlene Schutzmaßnahmen:**
* **Air-Gapped System:** Root-CA-Operationen auf isoliertem Computer ohne Netzwerk
* **HSM:** Hardware Security Module für Schlüsselspeicherung (z.B. YubiHSM, Thales Luna)
* **Verschlüsselung:** Mindestens AES-256 mit starkem Passwort (≥20 Zeichen)
* **Physische Sicherheit:** Verschlüsselter USB-Stick im Tresor oder Bankschließfach
* **Backup:** Mindestens 2 Kopien an getrennten Standorten
* **Key Ceremony:** Dokumentierter Prozess mit Zeugen für alle Root-CA-Operationen
* **Audit-Log:** Alle Zugriffe protokollieren
**Best Practices:**
* **ML-DSA-65** bietet gutes Verhältnis von Sicherheit und Performance für Root-CAs
* **pathLength=1** begrenzt die Hierarchie auf Root → Intermediate → End-Entity
* **20 Jahre Gültigkeit** ist üblich für Root-CAs (max. 25 Jahre empfohlen)
* **SKI setzen** ermöglicht spätere AKI-Referenzierung in Intermediate-Zertifikaten
* **Selbsttest** nach Generierung stellt korrekte Implementierung sicher
----
===== Häufige Fehler =====
^ Problem ^ Ursache ^ Lösung ^
| ''KEY_GENERATION_FAILED'' | Nicht genug Entropie | OS-Zufallsquelle prüfen, /dev/urandom verfügbar? |
| ''KEYPAIR_SELF_TEST_FAILED'' | Defekte Implementierung | Bibliotheksversion prüfen, neu kompilieren |
| Zertifikat ungültig | DN leer | Mindestens CN setzen |
| Key nicht lesbar | Falsches Passwort | Passwort prüfen, Encoding (UTF-8) |
| pathLength-Fehler | Wert < -1 | -1 für unbegrenzt, 0, 1, 2, ... für Limit |
| ''NOT_INITIALIZED'' | ''init()'' vergessen | ''wvds_sec_crypto_x509_init()'' zuerst aufrufen |
| Speicherleck | Handles nicht freigegeben | Alle ''free_*()'' Funktionen aufrufen |
| PEM zu groß | Buffer zu klein | Größe vorher abfragen (out_len = 0) |
----
===== Verwandte Szenarien =====
^ Beziehung ^ Szenario ^ Beschreibung ^
| **Nächster Schritt** | [[.:intermediate_ca_erstellen|1.2 Intermediate-CA]] | Untergeordnete CA von Root signieren |
| **Dann** | [[.:trust_store_konfigurieren|1.4 Trust Store]] | Root-Zertifikat verteilen |
| **Dann** | [[.:crl_ocsp_infrastruktur|1.6 CRL/OCSP]] | Revocation-Dienste einrichten |
| **Alternativ** | [[de:int:pqcrypt:szenarien:schluessel:schluesselpaar_generieren|11.1 Schlüssel generieren]] | Nur Keys, kein Zertifikat |
| **Verwandt** | [[de:int:pqcrypt:szenarien:schluessel:schluessel_speichern|11.2 Schlüssel speichern]] | Weitere Speicheroptionen |
----
===== Referenzen =====
=== API-Dokumentation ===
* [[de:int:pqcrypt:api:module:init|Modul: init]]
* [[de:int:pqcrypt:api:module:keypair|Modul: keypair]]
* [[de:int:pqcrypt:api:module:dn|Modul: dn]]
* [[de:int:pqcrypt:api:module:cert|Modul: cert]]
* [[de:int:pqcrypt:api:module:ext|Modul: ext]]
* [[de:int:pqcrypt:api:module:free|Modul: free]]
=== Konzepte ===
* [[de:int:pqcrypt:konzepte:fips_204_ml_dsa|ML-DSA (FIPS 204)]]
* [[de:int:pqcrypt:konzepte:pki_grundlagen|PKI-Grundlagen]]
* [[de:int:pqcrypt:konzepte:x509_erweiterungen|X.509 Extensions]]
=== Sicherheit ===
* [[de:int:pqcrypt:sicherheit:schluessellaengen|Empfohlene Schlüssellängen]]
* [[de:int:pqcrypt:sicherheit:secure_memory|Sichere Speicherverwaltung]]
=== Referenztabellen ===
* [[de:int:pqcrypt:referenz:oid_tabelle|OID-Tabelle]]
* [[de:int:pqcrypt:referenz:error_codes_tabelle|Error Codes]]
* [[de:int:pqcrypt:referenz:schluesselgroessen|Schlüsselgrößen]]
* [[de:int:pqcrypt:referenz:signaturgroessen|Signaturgrößen]]
=== Externe 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-Infrastruktur]] | [[de:int:pqcrypt:szenarien:start|▲ Szenarien]] | [[.:intermediate_ca_erstellen|1.2 Intermediate-CA →]] >>
{{tag>szenario pki root-ca ml-dsa-65 selbstsigniert keypair zertifikat fips-204}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//
~~NOTOC~~