====== Scenarij 1.2: Kreiranje Intermediate-CA ====== **Kategorija:** [[.:start|PKI infrastruktura]] \\ **Složenost:** ⭐⭐⭐ (Srednja) \\ **Preduvjeti:** [[.:root_ca_erstellen|Scenarij 1.1: Kreiranje Root-CA]] \\ **Procijenjeno vrijeme:** 20-40 minuta ---- ===== Opis ===== Ovaj scenarij opisuje kreiranje **Intermediate-CA** (također nazvanog Sub-CA ili Issuing-CA), koji je potpisan od Root-CA. Intermediate-CA izdaje certifikate krajnjih entiteta i štiti Root-CA ključ, koji može ostati offline. **Što se kreira:** * ML-DSA-65 par ključeva za Intermediate-CA * Certificate Signing Request (CSR) * Intermediate certifikat potpisan od Root-CA * Šifrirani privatni ključ **Prednosti Intermediate-CA:** * **Sigurnost:** Root-CA ostaje offline, samo Intermediate-CA online * **Fleksibilnost:** Više Intermediate-CA za različite namjene (Server, Client, Code-Signing) * **Opoziv:** Intermediate-CA može biti opozvan bez kompromitacije Root-a * **Usklađenost:** Odgovara best practices (CA/Browser Forum, BSI) **Tipični tipovi Intermediate-CA:** * **Server-CA:** Za TLS server certifikate * **Client-CA:** Za mTLS klijentske certifikate * **User-CA:** Za E-Mail/S-MIME certifikate * **CodeSign-CA:** Za Code-Signing certifikate * **Device-CA:** Za IoT/uređajne certifikate ---- ===== Dijagram tijeka ===== ┌─────────────────────────────────────────────────────────────────────────┐ │ KREIRANJE INTERMEDIATE-CA │ │ │ │ ┌─────────────────────────┐ ┌─────────────────────────┐ │ │ │ INTERMEDIATE-CA │ │ ROOT-CA │ │ │ │ (Online sustav) │ │ (Air-Gapped sustav) │ │ │ └─────────────────────────┘ └─────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────┘ ┌──────────────┐ │ 1. Init │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 2. KeyPair │ ──────► ML-DSA-65 za Intermediate │ generiranje │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 3. DN │ ──────► CN=WvdS Server CA │ kreiranje │ O=DATECpro GmbH └──────┬───────┘ │ ▼ ┌──────────────┐ │ 4. Extensions│ ──────► BasicConstraints, KeyUsage, EKU │ za CSR │ (željene ekstenzije) └──────┬───────┘ │ ▼ ┌──────────────┐ │ 5. CSR │ ──────► PKCS#10 zahtjev │ kreiranje │ Potpisan s Intermediate ključem └──────┬───────┘ │ │ ══════════════════════════════════════════ │ Prijenos CSR-a (USB stick, siguran kanal) ▼ ══════════════════════════════════════════ ┌──────────────┐ │ 6. Root-CA │ ──────► Učitavanje root-ca.key.pem │ učitavanje │ (Air-Gapped sustav) └──────┬───────┘ │ ▼ ┌──────────────┐ │ 7. CSR │ ──────► Provjera: DN, potpis, ekstenzije │ validacija │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 8. Extensions│ ──────► BC, KU, SKI, AKI, CDP, AIA │ postavljanje │ (CA određuje konačne ekstenzije) └──────┬───────┘ │ ▼ ┌──────────────┐ │ 9. Certifikat│ ──────► Root-CA potpisuje │ izdavanje │ Intermediate certifikat └──────┬───────┘ │ │ ══════════════════════════════════════════ │ Prijenos certifikata natrag ▼ ══════════════════════════════════════════ ┌──────────────┐ │ 10. Spremanje│ ──────► intermediate-ca.crt.pem │ │ intermediate-ca.key.pem └──────┬───────┘ │ ▼ ┌──────────────┐ │ 11. Chain │ ──────► Kreiranje ca-chain.pem │ kreiranje │ (Intermediate + Root) └──────┬───────┘ │ ▼ ┌──────────────┐ │ 12. Cleanup │ └──────────────┘ ---- ===== Uključene funkcije ===== ==== Strana Intermediate-CA (Kreiranje CSR-a) ==== ^ 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 | | 3a | ''wvds_sec_crypto_x509_dn_create()'' | ''x509-cert'' | Kreiranje DN handle-a | | 3b | ''wvds_sec_crypto_x509_dn_add_component()'' | ''x509-cert'' | Dodavanje CN, O, OU, C | | 4 | ''wvds_sec_crypto_x509_ext_set_*()'' | ''x509-cert'' | Željene ekstenzije | | 5a | ''wvds_sec_crypto_x509_csr_create()'' | ''x509-cert'' | Kreiranje CSR-a | | 5b | ''wvds_sec_crypto_x509_csr_sign()'' | ''ml-dsa'' | Potpisivanje CSR-a | | 5c | ''wvds_sec_crypto_x509_csr_to_pem()'' | ''pem-rfc7468'' | Izvoz CSR-a kao PEM | ==== Strana Root-CA (Izdavanje certifikata) ==== ^ Korak ^ FFI funkcija ^ Rust Crate ^ Opis ^ | 6a | ''wvds_sec_crypto_x509_cert_load_pem()'' | ''x509-parser'' | Učitavanje Root certifikata | | 6b | ''wvds_sec_crypto_x509_keypair_load_pem_encrypted()'' | ''pkcs8'', ''argon2'' | Učitavanje Root ključa | | 7a | ''wvds_sec_crypto_x509_csr_load_pem()'' | ''x509-cert'' | Učitavanje CSR-a | | 7b | ''wvds_sec_crypto_x509_csr_verify()'' | ''ml-dsa'' | Provjera potpisa CSR-a | | 7c | ''wvds_sec_crypto_x509_csr_get_subject()'' | ''x509-cert'' | Čitanje Subject-a | | 8a | ''wvds_sec_crypto_x509_ext_set_basic_constraints()'' | ''x509-cert'' | CA=true, pathLen=0 | | 8b | ''wvds_sec_crypto_x509_ext_set_key_usage()'' | ''x509-cert'' | keyCertSign, cRLSign | | 8c | ''wvds_sec_crypto_x509_ext_set_ski_from_csr()'' | ''sha2'' | SKI iz CSR PublicKey-a | | 8d | ''wvds_sec_crypto_x509_ext_set_aki_from_cert()'' | ''x509-parser'' | AKI = Root-SKI | | 8e | ''wvds_sec_crypto_x509_ext_set_crl_distribution_points()'' | ''x509-cert'' | CRL URL | | 8f | ''wvds_sec_crypto_x509_ext_set_aia()'' | ''x509-cert'' | OCSP + CA Issuers URL | | 9 | ''wvds_sec_crypto_x509_cert_create_from_csr()'' | ''x509-cert'', ''ml-dsa'' | Kreiranje certifikata | | 10 | ''wvds_sec_crypto_x509_cert_to_pem()'' | ''pem-rfc7468'' | Izvoz certifikata | | 11 | ''wvds_sec_crypto_x509_chain_create()'' | – | Kreiranje Chain handle-a | ---- ===== Stablo funkcija ===== ═══════════════════════════════════════════════════════════════════════════ FAZA 1: Kreiranje CSR-a (Intermediate-CA sustav) ═══════════════════════════════════════════════════════════════════════════ wvds_sec_crypto_x509_init() │ ├── wvds_sec_crypto_x509_keypair_generate_mldsa(level: 65) → *mut KeyPairHandle │ └── ml_dsa::ml_dsa_65::KeyPair::generate(&mut OsRng) │ ├── wvds_sec_crypto_x509_dn_create() → *mut DnHandle │ ├── wvds_sec_crypto_x509_dn_add_component(dn, OID_CN, "WvdS Server CA") ├── wvds_sec_crypto_x509_dn_add_component(dn, OID_O, "DATECpro GmbH") ├── wvds_sec_crypto_x509_dn_add_component(dn, OID_OU, "PKI Services") ├── wvds_sec_crypto_x509_dn_add_component(dn, OID_C, "DE") │ ├── // Ekstenzije za CSR (opcijski, CA može prepisati) │ ├── wvds_sec_crypto_x509_ext_create() → *mut ExtHandle │ ├── wvds_sec_crypto_x509_ext_set_basic_constraints(ext, ca=true, path_len=0) │ └── wvds_sec_crypto_x509_ext_set_key_usage(ext, KEY_CERT_SIGN | CRL_SIGN) │ ├── wvds_sec_crypto_x509_csr_create(subject: dn, keypair, extensions) → *mut CsrHandle │ │ │ ├── // Izgradnja CertificationRequestInfo │ │ └── cri = x509_cert::request::CertReqInfo { │ │ version: 0, │ │ subject: dn.clone(), │ │ subject_public_key_info: keypair.to_spki(), │ │ attributes: extensions.to_csr_attributes() │ │ } │ │ │ └── // Potpisivanje CSR-a s Intermediate ključem │ └── wvds_sec_crypto_x509_csr_sign(csr, keypair) │ │ │ ├── cri_der = der::Encode::to_der(&cri) │ ├── signature = ml_dsa::ml_dsa_65::SigningKey::sign(&cri_der) │ │ │ └── csr = x509_cert::request::CertReq { │ info: cri, │ algorithm: OID_ML_DSA_65, │ signature: BitString::from_bytes(&signature) │ } │ ├── wvds_sec_crypto_x509_csr_to_pem(csr, out, out_len) → i32 │ └── pem_rfc7468::encode_string("CERTIFICATE REQUEST", &csr_der) │ ├── // Spremanje CSR-a na USB stick → Air-Gapped sustav │ └── wvds_sec_crypto_x509_keypair_to_pem_encrypted(keypair, password, ARGON2ID) └── // Sigurno spremanje Intermediate privatnog ključa ═══════════════════════════════════════════════════════════════════════════ FAZA 2: Izdavanje certifikata (Root-CA Air-Gapped sustav) ═══════════════════════════════════════════════════════════════════════════ wvds_sec_crypto_x509_init() │ ├── // Učitavanje Root-CA materijala │ │ │ ├── wvds_sec_crypto_x509_cert_load_pem(root_cert_pem) → *mut CertHandle │ │ └── x509_parser::parse_x509_certificate(&pem_decode(pem)) │ │ │ └── wvds_sec_crypto_x509_keypair_load_pem_encrypted(root_key_pem, password) → *mut KeyPairHandle │ ├── pem_rfc7468::decode("ENCRYPTED PRIVATE KEY", pem) │ ├── pkcs8::EncryptedPrivateKeyInfo::from_der(der) │ ├── kek = argon2::hash_password_into(password, salt) │ ├── private_key_der = aes_gcm::decrypt(kek, encrypted_data) │ └── KeyPair::from_pkcs8_der(private_key_der) │ ├── // Učitavanje i validacija CSR-a │ │ │ ├── wvds_sec_crypto_x509_csr_load_pem(csr_pem) → *mut CsrHandle │ │ └── x509_cert::request::CertReq::from_der(&pem_decode(pem)) │ │ │ ├── wvds_sec_crypto_x509_csr_verify(csr) → i32 │ │ │ │ │ ├── // Verifikacija potpisa │ │ │ ├── cri_der = der::Encode::to_der(&csr.info) │ │ │ ├── public_key = csr.info.subject_public_key_info │ │ │ └── ml_dsa::VerifyingKey::verify(&cri_der, &csr.signature) │ │ │ │ │ └── return WVDS_OK ili WVDS_ERROR_SIGNATURE_INVALID │ │ │ ├── wvds_sec_crypto_x509_csr_get_subject(csr) → *mut DnHandle │ │ └── csr.info.subject.clone() │ │ │ └── wvds_sec_crypto_x509_csr_get_public_key(csr) → *mut PublicKeyHandle │ └── csr.info.subject_public_key_info.clone() │ ├── // Ekstenzije za Intermediate certifikat │ │ │ ├── wvds_sec_crypto_x509_ext_create() → *mut ExtHandle │ │ │ ├── wvds_sec_crypto_x509_ext_set_basic_constraints(ext, ca=true, path_len=0) │ │ │ │ │ └── // pathLen=0: Ovaj CA smije izdavati samo End-Entity certifikate │ │ bc = BasicConstraints { ca: true, path_len_constraint: Some(0) } │ │ │ ├── wvds_sec_crypto_x509_ext_set_key_usage(ext, KEY_CERT_SIGN | CRL_SIGN) │ │ │ ├── wvds_sec_crypto_x509_ext_set_ski_from_public_key(ext, csr_public_key) │ │ └── ski = sha2::Sha256::digest(&public_key_bytes)[0..20] │ │ │ ├── wvds_sec_crypto_x509_ext_set_aki_from_cert(ext, root_cert) │ │ │ │ │ ├── // Authority Key Identifier = SKI Root-CA │ │ │ └── root_ski = root_cert.get_extension(OID_SKI) │ │ │ │ │ └── aki = AuthorityKeyIdentifier { │ │ key_identifier: Some(root_ski), │ │ authority_cert_issuer: None, │ │ authority_cert_serial: None │ │ } │ │ │ ├── wvds_sec_crypto_x509_ext_set_crl_distribution_points(ext, urls[], url_count) │ │ │ │ │ └── cdp = CrlDistributionPoints([ │ │ DistributionPoint { │ │ distribution_point: Some(FullName([ │ │ GeneralName::Uri("http://crl.example.com/root.crl") │ │ ])), │ │ reasons: None, │ │ crl_issuer: None │ │ } │ │ ]) │ │ │ ├── wvds_sec_crypto_x509_ext_set_aia(ext, ocsp_url, ca_issuers_url) │ │ │ │ │ └── aia = AuthorityInfoAccess([ │ │ AccessDescription { │ │ access_method: OID_OCSP, │ │ access_location: GeneralName::Uri("http://ocsp.example.com") │ │ }, │ │ AccessDescription { │ │ access_method: OID_CA_ISSUERS, │ │ access_location: GeneralName::Uri("http://ca.example.com/root.crt") │ │ } │ │ ]) │ │ │ └── // Opcijski: Certificate Policies, Name Constraints, itd. │ ├── // Serijski broj i valjanost │ │ │ ├── wvds_sec_crypto_x509_serial_generate(serial, 20) │ │ │ └── wvds_sec_crypto_x509_validity_create(now, now + 10 years) │ └── // Intermediate-CA: 8-12 godina (kraće od Root) │ ├── wvds_sec_crypto_x509_cert_create_from_csr( │ csr, │ issuer_cert: root_cert, │ issuer_key: root_keypair, │ serial, │ validity, │ extensions │ ) → *mut CertHandle │ │ │ ├── // Izgradnja TBSCertificate │ │ └── tbs = x509_cert::TbsCertificate { │ │ version: Version::V3, │ │ serial_number: SerialNumber::new(&serial), │ │ signature: AlgorithmIdentifier { oid: OID_ML_DSA_65 }, │ │ issuer: root_cert.subject(), // Issuer = Root-CA Subject │ │ validity: validity, │ │ subject: csr.info.subject, // Subject iz CSR-a │ │ subject_public_key_info: csr.info.subject_public_key_info, │ │ extensions: Some(extensions) │ │ } │ │ │ ├── // Potpisivanje s Root-CA │ │ └── signature = ml_dsa::SigningKey::sign(&tbs_der) │ │ │ └── cert = x509_cert::Certificate { tbs, signature_algorithm, signature } │ ├── wvds_sec_crypto_x509_cert_to_pem(intermediate_cert, out, out_len) │ └── pem_rfc7468::encode_string("CERTIFICATE", &cert_der) │ └── // Čišćenje ├── wvds_sec_crypto_x509_free_csr(csr) ├── wvds_sec_crypto_x509_free_cert(root_cert) ├── wvds_sec_crypto_x509_free_cert(intermediate_cert) ├── wvds_sec_crypto_x509_free_keypair(root_keypair) └── wvds_sec_crypto_x509_shutdown() ═══════════════════════════════════════════════════════════════════════════ FAZA 3: Deployment (Intermediate-CA sustav) ═══════════════════════════════════════════════════════════════════════════ wvds_sec_crypto_x509_init() │ ├── // Kreiranje lanca certifikata │ │ │ ├── wvds_sec_crypto_x509_cert_load_pem(intermediate_cert_pem) → intermediate │ ├── wvds_sec_crypto_x509_cert_load_pem(root_cert_pem) → root │ │ │ ├── wvds_sec_crypto_x509_chain_create() → *mut ChainHandle │ ├── wvds_sec_crypto_x509_chain_add_cert(chain, intermediate) │ ├── wvds_sec_crypto_x509_chain_add_cert(chain, root) │ │ │ └── wvds_sec_crypto_x509_chain_to_pem(chain, out, out_len) │ │ │ └── // ca-chain.pem: │ // -----BEGIN CERTIFICATE----- │ // (Intermediate-CA) │ // -----END CERTIFICATE----- │ // -----BEGIN CERTIFICATE----- │ // (Root-CA) │ // -----END CERTIFICATE----- │ ├── // Validacija │ │ │ ├── wvds_sec_crypto_x509_validate_chain(chain, trust_store) │ └── wvds_sec_crypto_x509_cert_verify_signature(intermediate, root) │ └── wvds_sec_crypto_x509_shutdown() ---- ===== Primjeri koda ===== === C# (.NET Wrapper) === using System; using System.IO; using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; namespace IntermediateCaExample { class Program { // Lozinke (u produkciji: sigurno unijeti!) const string ROOT_KEY_PASSWORD = "MyStr0ng!RootCA#Password2024"; const string INTERMEDIATE_KEY_PASSWORD = "MyStr0ng!IntermediateCA#2024"; static void Main(string[] args) { // === FAZA 1: Kreiranje CSR-a (Intermediate-CA sustav) === Console.WriteLine("=== FAZA 1: Kreiranje CSR-a ===\n"); using var context = PqCryptoContext.Initialize(); // 1. Generiranje para ključeva za Intermediate-CA Console.WriteLine("Generiram ML-DSA-65 par ključeva za Intermediate-CA..."); using var intermediateKeyPair = context.GenerateKeyPair(PqAlgorithm.MlDsa65); intermediateKeyPair.SelfTest(); // 2. Distinguished Name var intermediateDn = new DistinguishedNameBuilder() .AddCommonName("WvdS Server CA") .AddOrganization("DATECpro GmbH") .AddOrganizationalUnit("PKI Services") .AddCountry("DE") .Build(); Console.WriteLine($"Intermediate DN: {intermediateDn}"); // 3. Željene ekstenzije za CSR var csrExtensions = new X509ExtensionsBuilder() .AddBasicConstraints(isCa: true, pathLengthConstraint: 0, critical: true) .AddKeyUsage(KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign, critical: true) .Build(); // 4. Kreiranje i potpisivanje CSR-a Console.WriteLine("Kreiram Certificate Signing Request..."); using var csr = context.CreateCertificateRequest( subject: intermediateDn, keyPair: intermediateKeyPair, extensions: csrExtensions ); // 5. Spremanje CSR-a kao PEM string csrPem = csr.ExportToPem(); File.WriteAllText("intermediate-ca.csr.pem", csrPem); Console.WriteLine("CSR spremljen: intermediate-ca.csr.pem"); // 6. Šifrirano spremanje Intermediate privatnog ključa File.WriteAllText("intermediate-ca.key.pem", intermediateKeyPair.ExportToEncryptedPem(INTERMEDIATE_KEY_PASSWORD)); Console.WriteLine("Privatni ključ spremljen: intermediate-ca.key.pem\n"); // === FAZA 2: Izdavanje certifikata (Root-CA sustav) === Console.WriteLine("=== FAZA 2: Izdavanje certifikata od Root-CA ===\n"); // 7. Učitavanje Root-CA materijala Console.WriteLine("Učitavam Root-CA..."); using var rootCert = context.LoadCertificateFromPem( File.ReadAllText("root-ca.crt.pem") ); using var rootKeyPair = context.LoadKeyPairFromEncryptedPem( File.ReadAllText("root-ca.key.pem"), ROOT_KEY_PASSWORD ); Console.WriteLine($"Root-CA učitan: {rootCert.Subject}"); // 8. Učitavanje i validacija CSR-a Console.WriteLine("Učitavam i validiram CSR..."); using var loadedCsr = context.LoadCertificateRequestFromPem(csrPem); if (!loadedCsr.VerifySignature()) throw new CryptographicException("Potpis CSR-a nevažeći!"); Console.WriteLine("Potpis CSR-a: OK"); // 9. Ekstenzije za Intermediate certifikat (CA određuje) var certExtensions = new X509ExtensionsBuilder() // BasicConstraints: CA, ali bez daljnje Sub-CA .AddBasicConstraints(isCa: true, pathLengthConstraint: 0, critical: true) // KeyUsage: Potpisivanje certifikata i CRL-a .AddKeyUsage(KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign, critical: true) // Subject Key Identifier (iz CSR javnog ključa) .AddSubjectKeyIdentifier(loadedCsr.PublicKey) // Authority Key Identifier (= Root-CA SKI) .AddAuthorityKeyIdentifier(rootCert) // CRL Distribution Point .AddCrlDistributionPoint("http://crl.datecpro.de/root-ca.crl") // Authority Info Access (OCSP + CA Issuers) .AddAuthorityInfoAccess( ocspUri: "http://ocsp.datecpro.de", caIssuersUri: "http://ca.datecpro.de/root-ca.crt" ) .Build(); // 10. Valjanost: 10 godina (kraće od Root-CA) var validity = new CertificateValidity( notBefore: DateTime.UtcNow, notAfter: DateTime.UtcNow.AddYears(10) ); // 11. Izdavanje Intermediate-CA certifikata Console.WriteLine("Izdajem Intermediate-CA certifikat..."); using var intermediateCert = context.IssueCertificateFromRequest( request: loadedCsr, issuerCertificate: rootCert, issuerKeyPair: rootKeyPair, validity: validity, extensions: certExtensions ); // 12. Ispis informacija o certifikatu Console.WriteLine("\n=== INTERMEDIATE-CA CERTIFIKAT ==="); Console.WriteLine($"Subject: {intermediateCert.Subject}"); Console.WriteLine($"Issuer: {intermediateCert.Issuer}"); Console.WriteLine($"Serial: {intermediateCert.SerialNumber}"); Console.WriteLine($"Not Before: {intermediateCert.NotBefore:yyyy-MM-dd}"); Console.WriteLine($"Not After: {intermediateCert.NotAfter:yyyy-MM-dd}"); Console.WriteLine($"Algoritam: {intermediateCert.SignatureAlgorithm}"); Console.WriteLine($"Is CA: {intermediateCert.IsCertificateAuthority}"); Console.WriteLine($"Path Length: {intermediateCert.PathLengthConstraint}"); Console.WriteLine($"Thumbprint: {intermediateCert.Thumbprint}"); // 13. Spremanje certifikata File.WriteAllText("intermediate-ca.crt.pem", intermediateCert.ExportToPem()); Console.WriteLine("\nCertifikat spremljen: intermediate-ca.crt.pem"); // === FAZA 3: Kreiranje lanca === Console.WriteLine("\n=== FAZA 3: Lanac certifikata ===\n"); // 14. Kreiranje CA-Chain-a (Intermediate + Root) using var chain = context.CreateCertificateChain(); chain.Add(intermediateCert); chain.Add(rootCert); File.WriteAllText("ca-chain.pem", chain.ExportToPem()); Console.WriteLine("CA-Chain spremljen: ca-chain.pem"); // 15. Validacija Console.WriteLine("\n=== VALIDACIJA ==="); // Provjera potpisa (Intermediate potpisan od Root?) bool signatureValid = intermediateCert.VerifySignature(rootCert); Console.WriteLine($"Potpis od Root-CA: {(signatureValid ? "OK" : "GREŠKA")}"); // Validacija lanca using var trustStore = context.CreateTrustStore(); trustStore.AddCertificate(rootCert); var validationResult = context.ValidateChain(chain, trustStore); Console.WriteLine($"Validacija lanca: {(validationResult.IsValid ? "OK" : "GREŠKA")}"); Console.WriteLine("\n✓ Intermediate-CA uspješno kreiran!"); } } } === Delphi (FFI) === program CreateIntermediateCA; {$APPTYPE CONSOLE} uses SysUtils, DateUtils, Classes, WvdS.PqCrypto.FFI; const ROOT_KEY_PASSWORD = 'MyStr0ng!RootCA#Password2024'; INTERMEDIATE_KEY_PASSWORD = 'MyStr0ng!IntermediateCA#2024'; var res: Integer; // Intermediate-CA intKeyPair: Pointer; intDn: Pointer; intExt: Pointer; csr: Pointer; intCert: Pointer; // Root-CA rootCert: Pointer; rootKeyPair: Pointer; // Kreiranje certifikata certExt: Pointer; validity: Pointer; serial: array[0..19] of Byte; chain: Pointer; // Buffer pem_buf: array[0..65535] of AnsiChar; pem_len: NativeUInt; function LoadFileToString(const FileName: string): AnsiString; begin with TStringList.Create do try LoadFromFile(FileName); Result := AnsiString(Text); finally Free; end; end; procedure SaveStringToFile(const FileName: string; const Content: AnsiString); begin with TFileStream.Create(FileName, fmCreate) do try Write(Content[1], Length(Content)); finally Free; end; end; begin WriteLn('=== WvdS Kreiranje Intermediate-CA ==='); WriteLn; res := wvds_sec_crypto_x509_init(); if res <> WVDS_OK then begin WriteLn('GREŠKA: Inicijalizacija neuspješna'); Exit; end; try // ═══════════════════════════════════════════════════════════ // FAZA 1: Kreiranje CSR-a // ═══════════════════════════════════════════════════════════ WriteLn('=== FAZA 1: Kreiranje CSR-a ==='); WriteLn; // 1. Generiranje para ključeva WriteLn('Generiram ML-DSA-65 par ključeva...'); intKeyPair := wvds_sec_crypto_x509_keypair_generate_mldsa(65); if intKeyPair = nil then raise Exception.Create('Generiranje para ključeva neuspješno'); // 2. Distinguished Name intDn := wvds_sec_crypto_x509_dn_create(); wvds_sec_crypto_x509_dn_add_component(intDn, '2.5.4.3', 'WvdS Server CA'); wvds_sec_crypto_x509_dn_add_component(intDn, '2.5.4.10', 'DATECpro GmbH'); wvds_sec_crypto_x509_dn_add_component(intDn, '2.5.4.11', 'PKI Services'); wvds_sec_crypto_x509_dn_add_component(intDn, '2.5.4.6', 'DE'); // 3. Ekstenzije za CSR intExt := wvds_sec_crypto_x509_ext_create(); wvds_sec_crypto_x509_ext_set_basic_constraints(intExt, True, 0); wvds_sec_crypto_x509_ext_set_key_usage(intExt, $0006); // keyCertSign + cRLSign // 4. Kreiranje CSR-a WriteLn('Kreiram CSR...'); csr := wvds_sec_crypto_x509_csr_create(intDn, intKeyPair, intExt); if csr = nil then raise Exception.Create('Kreiranje CSR-a neuspješno'); // 5. Potpisivanje CSR-a res := wvds_sec_crypto_x509_csr_sign(csr, intKeyPair); if res <> WVDS_OK then raise Exception.Create('Potpisivanje CSR-a neuspješno'); // 6. Spremanje CSR-a kao PEM pem_len := SizeOf(pem_buf); wvds_sec_crypto_x509_csr_to_pem(csr, @pem_buf[0], @pem_len); SaveStringToFile('intermediate-ca.csr.pem', pem_buf); WriteLn('CSR spremljen: intermediate-ca.csr.pem'); // 7. Spremanje privatnog ključa pem_len := SizeOf(pem_buf); wvds_sec_crypto_x509_keypair_to_pem_encrypted( intKeyPair, INTERMEDIATE_KEY_PASSWORD, WVDS_KDF_ARGON2ID, @pem_buf[0], @pem_len ); SaveStringToFile('intermediate-ca.key.pem', pem_buf); WriteLn('Privatni ključ spremljen: intermediate-ca.key.pem'); WriteLn; // ═══════════════════════════════════════════════════════════ // FAZA 2: Izdavanje certifikata od Root-CA // ═══════════════════════════════════════════════════════════ WriteLn('=== FAZA 2: Izdavanje certifikata ==='); WriteLn; // 8. Učitavanje Root-CA WriteLn('Učitavam Root-CA...'); rootCert := wvds_sec_crypto_x509_cert_load_pem( PAnsiChar(LoadFileToString('root-ca.crt.pem')) ); if rootCert = nil then raise Exception.Create('Učitavanje Root certifikata neuspješno'); rootKeyPair := wvds_sec_crypto_x509_keypair_load_pem_encrypted( PAnsiChar(LoadFileToString('root-ca.key.pem')), ROOT_KEY_PASSWORD ); if rootKeyPair = nil then raise Exception.Create('Učitavanje Root ključa neuspješno'); // 9. Validacija CSR-a WriteLn('Validiram CSR...'); res := wvds_sec_crypto_x509_csr_verify(csr); if res <> WVDS_OK then raise Exception.Create('Potpis CSR-a nevažeći'); WriteLn('Potpis CSR-a: OK'); // 10. Ekstenzije za certifikat certExt := wvds_sec_crypto_x509_ext_create(); wvds_sec_crypto_x509_ext_set_basic_constraints(certExt, True, 0); wvds_sec_crypto_x509_ext_set_key_usage(certExt, $0006); wvds_sec_crypto_x509_ext_set_ski_from_csr(certExt, csr); wvds_sec_crypto_x509_ext_set_aki_from_cert(certExt, rootCert); wvds_sec_crypto_x509_ext_set_crl_distribution_points( certExt, PAnsiChar('http://crl.datecpro.de/root-ca.crl'), 1 ); wvds_sec_crypto_x509_ext_set_aia( certExt, 'http://ocsp.datecpro.de', 'http://ca.datecpro.de/root-ca.crt' ); // 11. Serijski broj i valjanost wvds_sec_crypto_x509_serial_generate(@serial[0], 20); validity := wvds_sec_crypto_x509_validity_create( DateTimeToUnix(Now, False), DateTimeToUnix(IncYear(Now, 10), False) // 10 godina ); // 12. Izdavanje certifikata WriteLn('Izdajem certifikat...'); intCert := wvds_sec_crypto_x509_cert_create_from_csr( csr, rootCert, rootKeyPair, @serial[0], 20, validity, certExt ); if intCert = nil then raise Exception.Create('Kreiranje certifikata neuspješno'); // 13. Spremanje certifikata pem_len := SizeOf(pem_buf); wvds_sec_crypto_x509_cert_to_pem(intCert, @pem_buf[0], @pem_len); SaveStringToFile('intermediate-ca.crt.pem', pem_buf); WriteLn('Certifikat spremljen: intermediate-ca.crt.pem'); WriteLn; // ═══════════════════════════════════════════════════════════ // FAZA 3: Kreiranje lanca // ═══════════════════════════════════════════════════════════ WriteLn('=== FAZA 3: CA-Chain ==='); WriteLn; chain := wvds_sec_crypto_x509_chain_create(); wvds_sec_crypto_x509_chain_add_cert(chain, intCert); wvds_sec_crypto_x509_chain_add_cert(chain, rootCert); pem_len := SizeOf(pem_buf); wvds_sec_crypto_x509_chain_to_pem(chain, @pem_buf[0], @pem_len); SaveStringToFile('ca-chain.pem', pem_buf); WriteLn('CA-Chain spremljen: ca-chain.pem'); WriteLn; WriteLn('=== Intermediate-CA uspješno kreiran! ==='); finally // Čišćenje if chain <> nil then wvds_sec_crypto_x509_free_chain(chain); if intCert <> nil then wvds_sec_crypto_x509_free_cert(intCert); if certExt <> nil then wvds_sec_crypto_x509_free_ext(certExt); if validity <> nil then wvds_sec_crypto_x509_free_validity(validity); if rootKeyPair <> nil then wvds_sec_crypto_x509_free_keypair(rootKeyPair); if rootCert <> nil then wvds_sec_crypto_x509_free_cert(rootCert); if csr <> nil then wvds_sec_crypto_x509_free_csr(csr); if intExt <> nil then wvds_sec_crypto_x509_free_ext(intExt); if intDn <> nil then wvds_sec_crypto_x509_free_dn(intDn); if intKeyPair <> nil then wvds_sec_crypto_x509_free_keypair(intKeyPair); wvds_sec_crypto_x509_shutdown(); end; end. ---- ===== Ekstenzije za Intermediate-CA ===== ^ Ekstenzija ^ OID ^ Vrijednost ^ Critical ^ Opis ^ | Basic Constraints | 2.5.29.19 | CA=true, pathLen=0 | ✅ Da | Bez daljnje Sub-CA | | Key Usage | 2.5.29.15 | keyCertSign, cRLSign | ✅ Da | Samo potpisivanje certifikata/CRL-a | | Subject Key Identifier | 2.5.29.14 | SHA-256(publicKey) | ❌ Ne | Jedinstveni ID ključa | | Authority Key Identifier | 2.5.29.35 | Root-CA SKI | ❌ Ne | Referenca na Issuer ključ | | CRL Distribution Points | 2.5.29.31 | URL(s) | ❌ Ne | Gdje je CRL dostupan | | Authority Info Access | 1.3.6.1.5.5.7.1.1 | OCSP + caIssuers | ❌ Ne | OCSP URL i URL CA certifikata | | Certificate Policies | 2.5.29.32 | Policy OID(s) | ❌ Ne | Opcijski: Pravila izdavanja | | Extended Key Usage | 2.5.29.37 | Opcijski | ❌ Ne | Opcijski: Ograničenje namjene | ---- ===== Razlike u odnosu na Root-CA ===== ^ Aspekt ^ Root-CA ^ Intermediate-CA ^ | **Issuer** | = Subject (samopotpisan) | = Root-CA Subject | | **Potpisuje** | Vlastiti ključ | Root-CA ključ | | **pathLength** | 1 ili 2 | 0 (samo End-Entity) | | **Valjanost** | 15-25 godina | 8-12 godina | | **AKI** | Nije prisutan | Root-CA SKI | | **CDP** | Opcijski | Obavezan | | **AIA** | Nije prisutan | OCSP + caIssuers | | **Pohrana ključa** | Offline / HSM | Online (zaštićeno) | | **Uporaba** | Samo potpisivanje Intermediate-CA | Potpisivanje End-Entity certifikata | ---- ===== Sigurnosne napomene ===== **Zaštita ključa Intermediate-CA:** * Privatni ključ **šifrirano** pohraniti (Argon2id + AES-256-GCM) * Idealno u **HSM-u** ili hardverskom tokenu * **Ograničiti** pristup (samo CA servis) * **Audit logging** za sve operacije potpisivanja * Planirati redovitu **rotaciju ključeva** **Best Practices:** * **pathLength=0** sprječava daljnje Sub-CA ispod ovog Intermediate-CA * **Odvojeni Intermediate-CA** za različite namjene (Server, Client, Code-Signing) * **CDP i AIA** uvijek postaviti za provjeru opoziva * **CSR prenijeti offline** (USB stick) na Air-Gapped Root-CA sustav * **Lanac certifikata** (ca-chain.pem) pripremiti za jednostavan deployment **Izbjegavajte česte greške:** * **Ne** kreirati Intermediate-CA s istim ključem kao Root * **Ne** postavljati pathLength > 0 ako nije potrebna Sub-Sub-CA * **Ne** zaboraviti AKI (otežava izgradnju lanca) * **Ne** zaboraviti CDP/AIA (provjera opoziva neće raditi) ---- ===== Izlazne datoteke ===== ^ Datoteka ^ Tip ^ Opis ^ | ''intermediate-ca.csr.pem'' | PKCS#10 | Certificate Signing Request | | ''intermediate-ca.key.pem'' | PKCS#8 (encrypted) | Šifrirani privatni ključ | | ''intermediate-ca.crt.pem'' | X.509 | Intermediate-CA certifikat | | ''ca-chain.pem'' | PEM Bundle | Intermediate + Root (za deployment) | ---- ===== Povratne vrijednosti ===== ^ Kod ^ Konstanta ^ Značenje ^ | 0 | ''WVDS_OK'' | Uspjeh | | 1 | ''WVDS_ERROR_INVALID_PARAMETER'' | Nevaljani parametar | | 105 | ''WVDS_ERROR_INVALID_CSR'' | Nevažeći format CSR-a | | 202 | ''WVDS_ERROR_SIGNATURE_INVALID'' | Nevažeći potpis CSR-a | | 208 | ''WVDS_ERROR_WRONG_PASSWORD'' | Pogrešna lozinka Root ključa | ---- ===== Povezani scenariji ===== ^ Odnos ^ Scenarij ^ Opis ^ | **Preduvjet** | [[.:root_ca_erstellen|1.1 Kreiranje Root-CA]] | Root-CA mora postojati | | **Sljedeći korak** | [[.:trust_store_konfigurieren|1.4 Trust Store]] | Distribucija Root certifikata | | **Sljedeći korak** | [[.:crl_ocsp_infrastruktur|1.6 CRL/OCSP]] | Postavljanje opoziva | | **Zatim** | [[hr:int:pqcrypt:szenarien:zertifikate:server_zertifikat|3.1 Server certifikat]] | Izdavanje End-Entity certifikata | | **Alternativno** | [[.:ca_hierarchie_aufbauen|1.3 CA hijerarhija]] | Više Intermediate-CA | ---- ===== Reference ===== * [[hr:int:pqcrypt:api:module:csr|Modul: csr]] * [[hr:int:pqcrypt:api:module:cert|Modul: cert]] * [[hr:int:pqcrypt:api:module:ext|Modul: ext]] * [[hr:int:pqcrypt:api:module:chain|Modul: chain]] * [[hr:int:pqcrypt:konzepte:pki_grundlagen|Koncept: Osnove PKI]] * [[hr:int:pqcrypt:konzepte:x509_erweiterungen|Koncept: X.509 ekstenzije]] * [[https://www.rfc-editor.org/rfc/rfc5280|RFC 5280: X.509 PKI]] * [[https://cabforum.org/baseline-requirements/|CA/Browser Forum: Baseline Requirements]] ---- << [[.:root_ca_erstellen|← 1.1 Root-CA]] | [[.:start|▲ PKI infrastruktura]] | [[.:ca_hierarchie_aufbauen|1.3 CA hijerarhija →]] >> {{tag>scenarij pki intermediate-ca csr ml-dsa-65 chain aki cdp aia}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional// ~~NOTOC~~