====== 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~~