====== Scenarij 1.1: Kreiranje Root-CA s PQ ključevima ====== **Kategorija:** [[.:start|PKI infrastruktura]] \\ **Složenost:** ⭐⭐⭐⭐ (Visoka) \\ **Preduvjeti:** Nema (ulazna točka) \\ **Procijenjeno vrijeme:** 15-30 minuta ---- ===== Opis ===== Ovaj scenarij opisuje kreiranje **samopotpisanog Root-CA** s Post-Quantum ključevima. Root-CA čini **sidrište povjerenja (Trust Anchor)** za cijelu PKI hijerarhiju i najkritičniji je sigurnosni element infrastrukture. **Što se kreira:** * ML-DSA-65 par ključeva (Post-Quantum siguran) * Samopotpisani X.509 v3 Root certifikat * Šifrirani privatni ključ (PKCS#8 s Argon2id) **Slučajevi uporabe:** * Izgradnja nove PQ-spremne Enterprise PKI * Migracija postojeće PKI na Post-Quantum algoritme * Testno okruženje za PQ certifikate * Izolirana PKI za posebne primjene (IoT, Code-Signing) ---- ===== Dijagram tijeka ===== ┌─────────────────────────────────────────────────────────────────┐ │ KREIRANJE ROOT-CA │ └─────────────────────────────────────────────────────────────────┘ ┌──────────────┐ │ 1. Init │ │ Biblioteka │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 2. KeyPair │ ──────► ML-DSA-65 (FIPS 204) │ generiranje │ ~4KB javni ključ └──────┬───────┘ ~2KB privatni ključ │ ▼ ┌──────────────┐ │ 3. DN │ ──────► CN=WvdS Root CA │ kreiranje │ O=DATECpro GmbH └──────┬───────┘ C=DE │ ▼ ┌──────────────┐ │ 4. Serial │ ──────► 20 bajtova slučajnih (160 bit) │ generiranje │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 5. Validity │ ──────► notBefore: sada │ postavljanje │ notAfter: +20 godina └──────┬───────┘ │ ▼ ┌──────────────┐ │ 6. Extensions│ ──────► BasicConstraints: CA=true, pathLen=1 │ postavljanje │ KeyUsage: keyCertSign, cRLSign └──────┬───────┘ SKI: SHA-256(publicKey) │ ▼ ┌──────────────┐ │ 7. Certifikat│ ──────► Subject = Issuer (samopotpisan) │ kreiranje │ Potpis s ML-DSA-65 └──────┬───────┘ │ ▼ ┌──────────────┐ │ 8. Export │ ──────► root-ca.crt.pem (certifikat) │ PEM │ root-ca.key.pem (šifrirano) └──────┬───────┘ │ ▼ ┌──────────────┐ │ 9. Cleanup │ ──────► Oslobađanje handle-a │ │ Brisanje tajni (zeroize) └──────────────┘ ---- ===== Uključene funkcije ===== ^ Korak ^ FFI funkcija ^ Rust Crate ^ Opis ^ | 1 | ''wvds_sec_crypto_x509_init()'' | ''std::sync'' | Inicijalizacija biblioteke | | 2 | ''wvds_sec_crypto_x509_keypair_generate_mldsa(65)'' | ''ml-dsa'' | ML-DSA-65 par ključeva | | 2a | ''wvds_sec_crypto_x509_keypair_self_test()'' | ''ml-dsa'' | Samotest (sign/verify) | | 3a | ''wvds_sec_crypto_x509_dn_create()'' | ''x509-cert'' | Kreiranje DN handle-a | | 3b | ''wvds_sec_crypto_x509_dn_add_component()'' | ''x509-cert'', ''der'' | Dodavanje CN, O, C | | 4 | ''wvds_sec_crypto_x509_serial_generate()'' | ''rand'' | 160-bitni serijski broj | | 5 | ''wvds_sec_crypto_x509_validity_create()'' | ''x509-cert'' | Razdoblje valjanosti | | 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'' | Kreiranje Root certifikata | | 8a | ''wvds_sec_crypto_x509_cert_to_pem()'' | ''pem-rfc7468'' | Certifikat kao PEM | | 8b | ''wvds_sec_crypto_x509_keypair_to_pem_encrypted()'' | ''argon2'', ''aes-gcm'' | Šifrirani ključ | | 9a | ''wvds_sec_crypto_x509_free_*()'' | ''std::alloc'' | Oslobađanje handle-a | | 9b | ''wvds_sec_crypto_x509_zeroize_keypair()'' | ''zeroize'' | Brisanje tajni | ---- ===== Stablo funkcija ===== wvds_sec_crypto_x509_init() │ ├── wvds_sec_crypto_x509_keypair_generate_mldsa(level: u8) → *mut KeyPairHandle │ │ │ ├── // Odabir parametara │ │ ├── [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) │ │ │ ├── // Samotest (FIPS zahtjev) │ │ ├── test_msg = [0x00..0x20] // 32 bajta testnih podataka │ │ ├── signature = signing_key.sign(&test_msg) │ │ └── assert!(verifying_key.verify(&test_msg, &signature).is_ok()) │ │ │ └── // Kreiranje handle-a │ └── 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 bajtova, pozitivan │ │ └── rand::rngs::OsRng.fill_bytes(&mut serial[0..len]) │ │ │ └── // Najviši bit na 0 (pozitivan) │ └── 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 za datume >= 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) // samo 1 Intermediate razina │ │ } │ │ │ └── ext.add(Extension { │ extn_id: OID_BASIC_CONSTRAINTS, │ critical: true, // MORA biti critical za CA │ extn_value: der::Encode::to_der(&bc) │ }) │ ├── wvds_sec_crypto_x509_ext_set_key_usage(ext, flags: u16) → i32 │ │ │ ├── // Za 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, // TREBALO BI biti 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 │ │ │ ├── // Izgradnja 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(), // samopotpisan: issuer = subject │ │ validity: validity.clone(), │ │ subject: subject.clone(), │ │ subject_public_key_info: keypair.to_spki(), │ │ extensions: Some(extensions.clone()) │ │ } │ │ │ ├── // DER kodiranje TBS-Certificate │ │ └── tbs_der = der::Encode::to_der(&tbs) │ │ │ ├── // Potpisivanje s ML-DSA-65 │ │ └── signature = ml_dsa::ml_dsa_65::SigningKey::sign(&tbs_der) │ │ │ │ │ └── // Deterministički potpis (FIPS 204) │ │ // Duljina potpisa: 3293 bajta │ │ │ └── // Sastavljanje 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) │ │ │ └── // Primjer izlaza: │ // -----BEGIN CERTIFICATE----- │ // MIIxxxxxx... │ // -----END CERTIFICATE----- │ ├── wvds_sec_crypto_x509_keypair_to_pem_encrypted( │ keypair, password, kdf_algorithm, out, out_len │ ) → i32 │ │ │ ├── // Privatni ključ kao PKCS#8 DER │ │ └── private_key_der = keypair.signing_key.to_pkcs8_der() │ │ │ ├── // Generiranje salta i nonce-a │ │ ├── salt = rand::OsRng.gen::<[u8; 16]>() │ │ └── nonce = rand::OsRng.gen::<[u8; 12]>() │ │ │ ├── // Derivacija Key Encryption Key-a │ │ └── [ARGON2ID] │ │ └── argon2::Argon2::new( │ │ Algorithm::Argon2id, │ │ Version::V0x13, │ │ Params::new(65536, 3, 4, Some(32)) // 64MB, 3 iter., 4 trake │ │ ).hash_password_into(password.as_bytes(), &salt, &mut kek) │ │ │ ├── // Šifriranje privatnog ključa │ │ └── encrypted = aes_gcm::Aes256Gcm::new(&kek) │ │ .encrypt(&nonce, private_key_der.as_ref()) │ │ │ ├── // Kreiranje EncryptedPrivateKeyInfo (PKCS#8) │ │ └── epki = pkcs8::EncryptedPrivateKeyInfo { │ │ encryption_algorithm: ..., │ │ encrypted_data: encrypted │ │ } │ │ │ ├── // PEM kodiranje │ │ └── pem_rfc7468::encode_string("ENCRYPTED PRIVATE KEY", &epki_der) │ │ │ └── // KEK brisanje │ └── zeroize::Zeroize::zeroize(&mut kek) │ └── // Čišćenje │ ├── wvds_sec_crypto_x509_free_cert(cert) ├── wvds_sec_crypto_x509_free_keypair(keypair) │ └── // Automatski Zeroize putem 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() ---- ===== Primjeri koda ===== === C# (.NET Wrapper) === using System; using System.IO; using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; namespace RootCaExample { class Program { static void Main(string[] args) { // Lozinka za privatni ključ (u produkciji: sigurno unijeti!) string keyPassword = "MyStr0ng!RootCA#Password2024"; // 1. Inicijalizacija konteksta using var context = PqCryptoContext.Initialize(); // 2. Generiranje ML-DSA-65 para ključeva Console.WriteLine("Generiram ML-DSA-65 par ključeva..."); using var keyPair = context.GenerateKeyPair(PqAlgorithm.MlDsa65); // Izvršavanje samotesta if (!keyPair.SelfTest()) throw new CryptographicException("KeyPair self-test failed!"); Console.WriteLine($" Javni ključ: {keyPair.PublicKeySize} bajtova"); Console.WriteLine($" Privatni ključ: {keyPair.PrivateKeySize} bajtova"); // 3. Kreiranje Distinguished Name 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. Razdoblje valjanosti (20 godina za Root-CA) var validity = new CertificateValidity( notBefore: DateTime.UtcNow, notAfter: DateTime.UtcNow.AddYears(20) ); // 5. Ekstenzije za Root-CA var extensions = new X509ExtensionsBuilder() // BasicConstraints: CA=true, max 1 Intermediate razina .AddBasicConstraints(isCa: true, pathLengthConstraint: 1, critical: true) // KeyUsage: samo potpisivanje certifikata i CRL-a .AddKeyUsage( KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign, critical: true ) // Subject Key Identifier za kasniju AKI referencu .AddSubjectKeyIdentifier(keyPair) .Build(); // 6. Kreiranje Root certifikata (samopotpisan) Console.WriteLine("Kreiram samopotpisani Root certifikat..."); using var rootCert = context.CreateRootCertificate( keyPair: keyPair, subject: subjectDn, validity: validity, extensions: extensions ); // 7. Ispis informacija o certifikatu Console.WriteLine("\n=== ROOT-CA CERTIFIKAT ==="); 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($"Algoritam: {rootCert.SignatureAlgorithm}"); Console.WriteLine($"Thumbprint: {rootCert.Thumbprint}"); Console.WriteLine($"Is CA: {rootCert.IsCertificateAuthority}"); Console.WriteLine($"Path Length: {rootCert.PathLengthConstraint}"); // 8. Spremanje kao PEM datoteke string certPath = "root-ca.crt.pem"; string keyPath = "root-ca.key.pem"; // Certifikat (javni) File.WriteAllText(certPath, rootCert.ExportToPem()); Console.WriteLine($"\nCertifikat spremljen: {certPath}"); // Privatni ključ (šifriran s Argon2id) File.WriteAllText(keyPath, keyPair.ExportToEncryptedPem( password: keyPassword, kdfAlgorithm: KeyDerivationAlgorithm.Argon2id )); Console.WriteLine($"Privatni ključ spremljen: {keyPath} (šifrirano)"); // 9. Validacija: Ponovno učitavanje certifikata i provjera Console.WriteLine("\n=== VALIDACIJA ==="); using var loadedCert = context.LoadCertificateFromPem(File.ReadAllText(certPath)); using var loadedKey = context.LoadKeyPairFromEncryptedPem( File.ReadAllText(keyPath), keyPassword ); // Verifikacija samopotpisa bool signatureValid = loadedCert.VerifySignature(loadedCert); // self-signed Console.WriteLine($"Samopotpis valjan: {signatureValid}"); // Provjera pripadnosti para ključeva bool keyMatch = loadedCert.PublicKeyMatches(loadedKey); Console.WriteLine($"Public Key Match: {keyMatch}"); Console.WriteLine("\n✓ Root-CA uspješno kreiran!"); } } } === Delphi (FFI) === program CreateRootCA; {$APPTYPE CONSOLE} uses SysUtils, DateUtils, WvdS.PqCrypto.FFI; // FFI unit s deklaracijama 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 kreiranje ==='); WriteLn; // 1. Inicijalizacija biblioteke res := wvds_sec_crypto_x509_init(); if res <> WVDS_OK then begin WriteLn('GREŠKA: Inicijalizacija neuspješna (', res, ')'); Exit; end; try // 2. Generiranje ML-DSA-65 para ključeva WriteLn('Generiram ML-DSA-65 par ključeva...'); keypair := wvds_sec_crypto_x509_keypair_generate_mldsa(65); if keypair = nil then raise Exception.Create('Generiranje para ključeva neuspješno'); // Samotest res := wvds_sec_crypto_x509_keypair_self_test(keypair); if res <> WVDS_OK then raise Exception.Create('Samotest para ključeva neuspješan'); WriteLn(' Samotest: OK'); // 3. Kreiranje Distinguished Name WriteLn('Kreiram Distinguished Name...'); dn := wvds_sec_crypto_x509_dn_create(); if dn = nil then raise Exception.Create('Kreiranje DN-a neuspješno'); 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. Generiranje serijskog broja (20 bajtova = 160 bita) WriteLn('Generiram serijski broj...'); res := wvds_sec_crypto_x509_serial_generate(@serial[0], 20); if res <> WVDS_OK then raise Exception.Create('Generiranje serijskog broja neuspješno'); // 5. Valjanost: 20 godina WriteLn('Postavljam razdoblje valjanosti (20 godina)...'); validity := wvds_sec_crypto_x509_validity_create( DateTimeToUnix(Now, False), // not_before: sada DateTimeToUnix(IncYear(Now, 20), False) // not_after: +20 godina ); if validity = nil then raise Exception.Create('Kreiranje valjanosti neuspješno'); // 6. Kreiranje ekstenzija WriteLn('Postavljam ekstenzije...'); ext := wvds_sec_crypto_x509_ext_create(); if ext = nil then raise Exception.Create('Kreiranje ekstenzija neuspješno'); // 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 neuspješno'); // 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 neuspješno'); // Subject Key Identifier res := wvds_sec_crypto_x509_ext_set_ski_from_keypair(ext, keypair); if res <> WVDS_OK then raise Exception.Create('SKI neuspješno'); // 7. Kreiranje Root certifikata (samopotpisan) WriteLn('Kreiram samopotpisani Root certifikat...'); cert := wvds_sec_crypto_x509_cert_create_root( keypair, // Par ključeva dn, // Subject (= Issuer kod Root) @serial[0], 20, // Serijski broj validity, // Valjanost ext // Ekstenzije ); if cert = nil then raise Exception.Create('Kreiranje certifikata neuspješno'); // 8. Spremanje kao PEM WriteLn; WriteLn('Spremam datoteke...'); // Certifikat 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('Izvoz certifikata neuspješan'); with TFileStream.Create('root-ca.crt.pem', fmCreate) do try Write(pem_buf[0], pem_len); finally Free; end; WriteLn(' root-ca.crt.pem spremljen'); // Privatni ključ (šifrirano) 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('Izvoz ključa neuspješan'); with TFileStream.Create('root-ca.key.pem', fmCreate) do try Write(pem_buf[0], pem_len); finally Free; end; WriteLn(' root-ca.key.pem spremljen (šifrirano)'); WriteLn; WriteLn('=== Root-CA uspješno kreiran! ==='); finally // 9. Čišćenje 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. ---- ===== Parametri ===== ==== wvds_sec_crypto_x509_keypair_generate_mldsa ==== ^ Parametar ^ Tip ^ Opis ^ Valjane vrijednosti ^ | ''level'' | ''u8'' | ML-DSA sigurnosna razina | ''44'', ''65'', ''87'' | ^ Razina ^ NIST sigurnost ^ Javni ključ ^ Privatni ključ ^ Potpis ^ | 44 | Razina 2 (~128-bit) | 1.312 bajtova | 2.560 bajtova | 2.420 bajtova | | 65 | Razina 3 (~192-bit) | 1.952 bajtova | 4.032 bajtova | 3.293 bajtova | | 87 | Razina 5 (~256-bit) | 2.592 bajtova | 4.896 bajtova | 4.595 bajtova | ==== wvds_sec_crypto_x509_dn_add_component ==== ^ Parametar ^ Tip ^ Opis ^ Primjer ^ | ''dn'' | ''*mut DnHandle'' | DN handle | – | | ''oid'' | ''*const c_char'' | OID kao string | ''"2.5.4.3"'' | | ''value'' | ''*const c_char'' | UTF-8 vrijednost | ''"WvdS Root CA"'' | ^ OID ^ Konstanta ^ Opis ^ Primjer vrijednosti ^ | 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 znaka) | ''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 ==== ^ Parametar ^ Tip ^ Opis ^ Vrijednost za Root-CA ^ | ''ext'' | ''*mut ExtHandle'' | Extension handle | – | | ''ca'' | ''bool'' | Je li CA certifikat | ''true'' | | ''path_len'' | ''i32'' | Max. duljina putanje (-1 = neograničeno) | ''1'' ili ''2'' | ==== wvds_sec_crypto_x509_ext_set_key_usage ==== ^ Flag ^ Bit ^ Vrijednost ^ Opis ^ | digitalSignature | 0 | 0x0080 | Digitalni potpisi | | nonRepudiation | 1 | 0x0040 | Neporecivost | | keyEncipherment | 2 | 0x0020 | Šifriranje ključeva | | dataEncipherment | 3 | 0x0010 | Šifriranje podataka | | keyAgreement | 4 | 0x0008 | Dogovor ključeva | | **keyCertSign** | 5 | 0x0004 | **Potpisivanje certifikata** ✓ | | **cRLSign** | 6 | 0x0002 | **Potpisivanje CRL-a** ✓ | | encipherOnly | 7 | 0x0001 | Samo šifriranje | **Za Root-CA:** ''flags = 0x0006'' (keyCertSign + cRLSign) ---- ===== Povratne vrijednosti ===== ^ Kod ^ Konstanta ^ Značenje ^ | 0 | ''WVDS_OK'' | Uspjeh | | 1 | ''WVDS_ERROR_INVALID_PARAMETER'' | Nevaljani parametar (npr. level ≠ 44/65/87) | | 2 | ''WVDS_ERROR_OUT_OF_MEMORY'' | Alokacija memorije neuspješna | | 3 | ''WVDS_ERROR_NOT_INITIALIZED'' | ''init()'' nije pozvan | | 200 | ''WVDS_ERROR_KEY_GENERATION_FAILED'' | Generiranje ključa neuspješno | | 201 | ''WVDS_ERROR_SIGNATURE_FAILED'' | Potpisivanje neuspješno | | 210 | ''WVDS_ERROR_KEYPAIR_SELF_TEST_FAILED'' | Samotest neuspješan | → //Potpuni popis:// [[hr:int:pqcrypt:referenz:error_codes_tabelle|Kodovi grešaka]] ---- ===== Izlazne datoteke ===== ==== root-ca.crt.pem ==== -----BEGIN CERTIFICATE----- MIIHxjCCBiagAwIBAgIUP7J2kM9x... (Base64-kodirani DER) ... -----END CERTIFICATE----- ^ Polje ^ Vrijednost ^ | Version | 3 (0x02) | | Serial | 20 bajtova slučajnih | | 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 godina | | Public Key | ML-DSA-65 (~1.952 bajtova) | | Extensions | BasicConstraints, KeyUsage, SKI | | Signature | ML-DSA-65 (~3.293 bajtova) | ==== root-ca.key.pem ==== -----BEGIN ENCRYPTED PRIVATE KEY----- MIIHbTBXBgkqhkiG9w0BBQ0w... (PKCS#8 EncryptedPrivateKeyInfo) ... -----END ENCRYPTED PRIVATE KEY----- ^ Polje ^ Vrijednost ^ | Format | PKCS#8 EncryptedPrivateKeyInfo | | KDF | Argon2id (64MB, 3 iteracije, 4 trake) | | Cipher | AES-256-GCM | | Key Size | ~4.032 bajtova (ML-DSA-65 privatni ključ) | ---- ===== Sigurnosne napomene ===== **KRITIČNO – Root-CA privatni ključ:** Privatni ključ Root-CA je **najkritičniji sigurnosni element** cijele PKI. Kompromitacija znači potpuni gubitak povjerenja! * **Nikada** ne generirati ili pohranjivati na mrežno povezanim sustavima * **Nikada** ne pohranjivati nešifrirano * **Nikada** ne prenositi e-mailom ili nesigurnim kanalima **Preporučene zaštitne mjere:** * **Air-Gapped sustav:** Root-CA operacije na izoliranom računalu bez mreže * **HSM:** Hardware Security Module za pohranu ključeva (npr. YubiHSM, Thales Luna) * **Šifriranje:** Minimalno AES-256 s jakom lozinkom (≥20 znakova) * **Fizička sigurnost:** Šifrirani USB stick u sefu ili bankovnom sefu * **Backup:** Minimalno 2 kopije na odvojenim lokacijama * **Key Ceremony:** Dokumentiran proces sa svjedocima za sve Root-CA operacije * **Audit log:** Protokolirati sve pristupe **Best Practices:** * **ML-DSA-65** pruža dobar omjer sigurnosti i performansi za Root-CA * **pathLength=1** ograničava hijerarhiju na Root → Intermediate → End-Entity * **20 godina valjanosti** je uobičajeno za Root-CA (max. 25 godina preporučeno) * **SKI postaviti** omogućuje kasniju AKI referencu u Intermediate certifikatima * **Samotest** nakon generiranja osigurava ispravnu implementaciju ---- ===== Česte greške ===== ^ Problem ^ Uzrok ^ Rješenje ^ | ''KEY_GENERATION_FAILED'' | Nedovoljno entropije | Provjeriti OS izvor slučajnosti, /dev/urandom dostupan? | | ''KEYPAIR_SELF_TEST_FAILED'' | Neispravna implementacija | Provjeriti verziju biblioteke, ponovno kompilirati | | Certifikat nevažeći | DN prazan | Minimalno postaviti CN | | Ključ nečitljiv | Pogrešna lozinka | Provjeriti lozinku, encoding (UTF-8) | | Greška pathLength | Vrijednost < -1 | -1 za neograničeno, 0, 1, 2, ... za ograničenje | | ''NOT_INITIALIZED'' | ''init()'' zaboravljen | Prvo pozvati ''wvds_sec_crypto_x509_init()'' | | Curenje memorije | Handle-i nisu oslobođeni | Pozvati sve ''free_*()'' funkcije | | PEM prevelik | Buffer premalen | Prethodno upitati veličinu (out_len = 0) | ---- ===== Povezani scenariji ===== ^ Odnos ^ Scenarij ^ Opis ^ | **Sljedeći korak** | [[.:intermediate_ca_erstellen|1.2 Intermediate-CA]] | Potpisivanje podređenog CA od Root-a | | **Zatim** | [[.:trust_store_konfigurieren|1.4 Trust Store]] | Distribucija Root certifikata | | **Zatim** | [[.:crl_ocsp_infrastruktur|1.6 CRL/OCSP]] | Postavljanje servisa za opoziv | | **Alternativno** | [[hr:int:pqcrypt:szenarien:schluessel:schluesselpaar_generieren|11.1 Generiranje ključeva]] | Samo ključevi, bez certifikata | | **Povezano** | [[hr:int:pqcrypt:szenarien:schluessel:schluessel_speichern|11.2 Pohrana ključeva]] | Dodatne opcije pohrane | ---- ===== Reference ===== === API dokumentacija === * [[hr:int:pqcrypt:api:module:init|Modul: init]] * [[hr:int:pqcrypt:api:module:keypair|Modul: keypair]] * [[hr:int:pqcrypt:api:module:dn|Modul: dn]] * [[hr:int:pqcrypt:api:module:cert|Modul: cert]] * [[hr:int:pqcrypt:api:module:ext|Modul: ext]] * [[hr:int:pqcrypt:api:module:free|Modul: free]] === Koncepti === * [[hr:int:pqcrypt:konzepte:fips_204_ml_dsa|ML-DSA (FIPS 204)]] * [[hr:int:pqcrypt:konzepte:pki_grundlagen|Osnove PKI]] * [[hr:int:pqcrypt:konzepte:x509_erweiterungen|X.509 ekstenzije]] === Sigurnost === * [[hr:int:pqcrypt:sicherheit:schluessellaengen|Preporučene duljine ključeva]] * [[hr:int:pqcrypt:sicherheit:secure_memory|Sigurno upravljanje memorijom]] === Referentne tablice === * [[hr:int:pqcrypt:referenz:oid_tabelle|OID tablica]] * [[hr:int:pqcrypt:referenz:error_codes_tabelle|Kodovi grešaka]] * [[hr:int:pqcrypt:referenz:schluesselgroessen|Veličine ključeva]] * [[hr:int:pqcrypt:referenz:signaturgroessen|Veličine potpisa]] === Vanjski standardi === * [[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 u X.509]] ---- << [[.:start|← PKI infrastruktura]] | [[hr:int:pqcrypt:szenarien:start|▲ Scenariji]] | [[.:intermediate_ca_erstellen|1.2 Intermediate-CA →]] >> {{tag>scenarij pki root-ca ml-dsa-65 samopotpisan keypair certifikat fips-204}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional// ~~NOTOC~~