Scenario 1.2: Creare Intermediate-CA
Categoria: Infrastruttura PKI
Complessità: Media
Prerequisiti: Scenario 1.1: Creare Root-CA
Tempo stimato: 20-40 minuti
Descrizione
Questo scenario descrive la creazione di una Intermediate-CA (chiamata anche Sub-CA o Issuing-CA), firmata dalla Root-CA. L'Intermediate-CA emette certificati end-entity e protegge la chiave Root-CA, che può rimanere offline.
Cosa viene creato:
- Coppia di chiavi ML-DSA-65 per Intermediate-CA
- Certificate Signing Request (CSR)
- Certificato Intermediate firmato dalla Root-CA
- Chiave privata crittografata
Vantaggi di una Intermediate-CA:
- Sicurezza: Root-CA rimane offline, solo Intermediate-CA online
- Flessibilità: Più Intermediate-CA per scopi diversi (Server, Client, Code-Signing)
- Revoca: Intermediate-CA può essere revocata senza compromettere Root
- Conformità: Corrisponde alle best practices (CA/Browser Forum, BSI)
Tipi tipici di Intermediate-CA:
- Server-CA: Per certificati TLS server
- Client-CA: Per certificati mTLS client
- User-CA: Per certificati E-Mail/S-MIME
- CodeSign-CA: Per certificati code-signing
- Device-CA: Per certificati IoT/dispositivi
Diagramma di flusso
┌─────────────────────────────────────────────────────────────────────────┐
│ CREAZIONE INTERMEDIATE-CA │
│ │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ INTERMEDIATE-CA │ │ ROOT-CA │ │
│ │ (Sistema Online) │ │ (Sistema Air-Gapped) │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
┌──────────────┐
│ 1. Init │
└──────┬───────┘
│
▼
┌──────────────┐
│ 2. KeyPair │ ──────► ML-DSA-65 per Intermediate
│ generare │
└──────┬───────┘
│
▼
┌──────────────┐
│ 3. DN │ ──────► CN=WvdS Server CA
│ creare │ O=DATECpro GmbH
└──────┬───────┘
│
▼
┌──────────────┐
│ 4. Extensions│ ──────► BasicConstraints, KeyUsage, EKU
│ per CSR │ (extensions desiderate)
└──────┬───────┘
│
▼
┌──────────────┐
│ 5. CSR │ ──────► PKCS#10 Request
│ creare │ Firmato con chiave Intermediate
└──────┬───────┘
│
│ ══════════════════════════════════════════
│ Trasferimento CSR (chiavetta USB, canale sicuro)
▼ ══════════════════════════════════════════
┌──────────────┐
│ 6. Root-CA │ ──────► Caricare root-ca.key.pem
│ caricare │ (Sistema Air-Gapped)
└──────┬───────┘
│
▼
┌──────────────┐
│ 7. CSR │ ──────► Verificare: DN, firma, extensions
│ validare │
└──────┬───────┘
│
▼
┌──────────────┐
│ 8. Extensions│ ──────► BC, KU, SKI, AKI, CDP, AIA
│ impostare │ (CA determina extensions finali)
└──────┬───────┘
│
▼
┌──────────────┐
│ 9. Certificato│ ──────► Root-CA firma
│ emettere │ certificato Intermediate
└──────┬───────┘
│
│ ══════════════════════════════════════════
│ Trasferimento certificato indietro
▼ ══════════════════════════════════════════
┌──────────────┐
│ 10. Salvare │ ──────► intermediate-ca.crt.pem
│ │ intermediate-ca.key.pem
└──────┬───────┘
│
▼
┌──────────────┐
│ 11. Chain │ ──────► Creare ca-chain.pem
│ creare │ (Intermediate + Root)
└──────┬───────┘
│
▼
┌──────────────┐
│ 12. Cleanup │
└──────────────┘
Funzioni coinvolte
Lato Intermediate-CA (Creazione CSR)
| Passo | Funzione FFI | Crate Rust | Descrizione |
|---|---|---|---|
| 1 | wvds_sec_crypto_x509_init() | std::sync | Inizializzare libreria |
| 2 | wvds_sec_crypto_x509_keypair_generate_mldsa(65) | ml-dsa | Coppia chiavi ML-DSA-65 |
| 3a | wvds_sec_crypto_x509_dn_create() | x509-cert | Creare handle DN |
| 3b | wvds_sec_crypto_x509_dn_add_component() | x509-cert | Aggiungere CN, O, OU, C |
| 4 | wvds_sec_crypto_x509_ext_set_*() | x509-cert | Extensions desiderate |
| 5a | wvds_sec_crypto_x509_csr_create() | x509-cert | Creare CSR |
| 5b | wvds_sec_crypto_x509_csr_sign() | ml-dsa | Firmare CSR |
| 5c | wvds_sec_crypto_x509_csr_to_pem() | pem-rfc7468 | Esportare CSR come PEM |
Lato Root-CA (Emissione certificato)
| Passo | Funzione FFI | Crate Rust | Descrizione |
|---|---|---|---|
| 6a | wvds_sec_crypto_x509_cert_load_pem() | x509-parser | Caricare certificato Root |
| 6b | wvds_sec_crypto_x509_keypair_load_pem_encrypted() | pkcs8, argon2 | Caricare chiave Root |
| 7a | wvds_sec_crypto_x509_csr_load_pem() | x509-cert | Caricare CSR |
| 7b | wvds_sec_crypto_x509_csr_verify() | ml-dsa | Verificare firma CSR |
| 7c | wvds_sec_crypto_x509_csr_get_subject() | x509-cert | Estrarre Subject |
| 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 da PublicKey CSR |
| 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 | URL CRL |
| 8f | wvds_sec_crypto_x509_ext_set_aia() | x509-cert | URL OCSP + CA Issuers |
| 9 | wvds_sec_crypto_x509_cert_create_from_csr() | x509-cert, ml-dsa | Creare certificato |
| 10 | wvds_sec_crypto_x509_cert_to_pem() | pem-rfc7468 | Esportare certificato |
| 11 | wvds_sec_crypto_x509_chain_create() | – | Creare handle Chain |
Albero delle funzioni
═══════════════════════════════════════════════════════════════════════════
FASE 1: Creazione CSR (Sistema Intermediate-CA)
═══════════════════════════════════════════════════════════════════════════
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")
│
├── // Extensions per CSR (opzionali, CA può sovrascrivere)
│ ├── 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
│ │
│ ├── // Costruire CertificationRequestInfo
│ │ └── cri = x509_cert::request::CertReqInfo {
│ │ version: 0,
│ │ subject: dn.clone(),
│ │ subject_public_key_info: keypair.to_spki(),
│ │ attributes: extensions.to_csr_attributes()
│ │ }
│ │
│ └── // Firmare CSR con chiave Intermediate
│ └── 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)
│
├── // Salvare CSR su chiavetta USB → Sistema Air-Gapped
│
└── wvds_sec_crypto_x509_keypair_to_pem_encrypted(keypair, password, ARGON2ID)
└── // Salvare in sicurezza chiave privata Intermediate
═══════════════════════════════════════════════════════════════════════════
FASE 2: Emissione certificato (Sistema Root-CA Air-Gapped)
═══════════════════════════════════════════════════════════════════════════
wvds_sec_crypto_x509_init()
│
├── // Caricare materiali Root-CA
│ │
│ ├── 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)
│
├── // Caricare e validare CSR
│ │
│ ├── 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
│ │ │
│ │ ├── // Verificare firma
│ │ │ ├── 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 o 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()
│
├── // Extensions per certificato Intermediate
│ │
│ ├── wvds_sec_crypto_x509_ext_create() → *mut ExtHandle
│ │
│ ├── wvds_sec_crypto_x509_ext_set_basic_constraints(ext, ca=true, path_len=0)
│ │ │
│ │ └── // pathLen=0: Questa CA può emettere solo certificati End-Entity
│ │ 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 della 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")
│ │ }
│ │ ])
│ │
│ └── // Opzionale: Certificate Policies, Name Constraints, ecc.
│
├── // Numero seriale e validità
│ │
│ ├── wvds_sec_crypto_x509_serial_generate(serial, 20)
│ │
│ └── wvds_sec_crypto_x509_validity_create(now, now + 10 years)
│ └── // Intermediate-CA: 8-12 anni (più breve di Root)
│
├── wvds_sec_crypto_x509_cert_create_from_csr(
│ csr,
│ issuer_cert: root_cert,
│ issuer_key: root_keypair,
│ serial,
│ validity,
│ extensions
│ ) → *mut CertHandle
│ │
│ ├── // Costruire 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 da CSR
│ │ subject_public_key_info: csr.info.subject_public_key_info,
│ │ extensions: Some(extensions)
│ │ }
│ │
│ ├── // Firmare con 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)
│
└── // Cleanup
├── 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()
═══════════════════════════════════════════════════════════════════════════
FASE 3: Deployment (Sistema Intermediate-CA)
═══════════════════════════════════════════════════════════════════════════
wvds_sec_crypto_x509_init()
│
├── // Creare catena certificati
│ │
│ ├── 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-----
│
├── // Validazione
│ │
│ ├── wvds_sec_crypto_x509_validate_chain(chain, trust_store)
│ └── wvds_sec_crypto_x509_cert_verify_signature(intermediate, root)
│
└── wvds_sec_crypto_x509_shutdown()
Esempi di codice
C# (.NET Wrapper)
using System; using System.IO; using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; namespace IntermediateCaExample { class Program { // Password (in produzione: inserire in modo sicuro!) const string ROOT_KEY_PASSWORD = "MyStr0ng!RootCA#Password2024"; const string INTERMEDIATE_KEY_PASSWORD = "MyStr0ng!IntermediateCA#2024"; static void Main(string[] args) { // === FASE 1: Creare CSR (Sistema Intermediate-CA) === Console.WriteLine("=== FASE 1: Creazione CSR ===\n"); using var context = PqCryptoContext.Initialize(); // 1. Generare coppia chiavi per Intermediate-CA Console.WriteLine("Generazione coppia chiavi ML-DSA-65 per 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. Extensions desiderate per CSR var csrExtensions = new X509ExtensionsBuilder() .AddBasicConstraints(isCa: true, pathLengthConstraint: 0, critical: true) .AddKeyUsage(KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign, critical: true) .Build(); // 4. Creare e firmare CSR Console.WriteLine("Creazione Certificate Signing Request..."); using var csr = context.CreateCertificateRequest( subject: intermediateDn, keyPair: intermediateKeyPair, extensions: csrExtensions ); // 5. Salvare CSR come PEM string csrPem = csr.ExportToPem(); File.WriteAllText("intermediate-ca.csr.pem", csrPem); Console.WriteLine("CSR salvato: intermediate-ca.csr.pem"); // 6. Salvare chiave privata Intermediate crittografata File.WriteAllText("intermediate-ca.key.pem", intermediateKeyPair.ExportToEncryptedPem(INTERMEDIATE_KEY_PASSWORD)); Console.WriteLine("Chiave privata salvata: intermediate-ca.key.pem\n"); // === FASE 2: Emettere certificato (Sistema Root-CA) === Console.WriteLine("=== FASE 2: Emissione certificato da Root-CA ===\n"); // 7. Caricare materiali Root-CA Console.WriteLine("Caricamento 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 caricata: {rootCert.Subject}"); // 8. Caricare e validare CSR Console.WriteLine("Caricamento e validazione CSR..."); using var loadedCsr = context.LoadCertificateRequestFromPem(csrPem); if (!loadedCsr.VerifySignature()) throw new CryptographicException("Firma CSR non valida!"); Console.WriteLine("Firma CSR: OK"); // 9. Extensions per certificato Intermediate (CA determina) var certExtensions = new X509ExtensionsBuilder() // BasicConstraints: CA, ma nessuna ulteriore Sub-CA consentita .AddBasicConstraints(isCa: true, pathLengthConstraint: 0, critical: true) // KeyUsage: Firma certificati e CRL .AddKeyUsage(KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign, critical: true) // Subject Key Identifier (da chiave pubblica CSR) .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. Validità: 10 anni (più breve di Root-CA) var validity = new CertificateValidity( notBefore: DateTime.UtcNow, notAfter: DateTime.UtcNow.AddYears(10) ); // 11. Emettere certificato Intermediate Console.WriteLine("Emissione certificato Intermediate-CA..."); using var intermediateCert = context.IssueCertificateFromRequest( request: loadedCsr, issuerCertificate: rootCert, issuerKeyPair: rootKeyPair, validity: validity, extensions: certExtensions ); // 12. Visualizzare informazioni certificato Console.WriteLine("\n=== CERTIFICATO INTERMEDIATE-CA ==="); 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($"Algorithm: {intermediateCert.SignatureAlgorithm}"); Console.WriteLine($"Is CA: {intermediateCert.IsCertificateAuthority}"); Console.WriteLine($"Path Length: {intermediateCert.PathLengthConstraint}"); Console.WriteLine($"Thumbprint: {intermediateCert.Thumbprint}"); // 13. Salvare certificato File.WriteAllText("intermediate-ca.crt.pem", intermediateCert.ExportToPem()); Console.WriteLine("\nCertificato salvato: intermediate-ca.crt.pem"); // === FASE 3: Creare Chain === Console.WriteLine("\n=== FASE 3: Certificate Chain ===\n"); // 14. Creare CA-Chain (Intermediate + Root) using var chain = context.CreateCertificateChain(); chain.Add(intermediateCert); chain.Add(rootCert); File.WriteAllText("ca-chain.pem", chain.ExportToPem()); Console.WriteLine("CA-Chain salvata: ca-chain.pem"); // 15. Validazione Console.WriteLine("\n=== VALIDAZIONE ==="); // Verificare firma (Intermediate firmato da Root?) bool signatureValid = intermediateCert.VerifySignature(rootCert); Console.WriteLine($"Firma da Root-CA: {(signatureValid ? "OK" : "ERRORE")}"); // Validazione Chain using var trustStore = context.CreateTrustStore(); trustStore.AddCertificate(rootCert); var validationResult = context.ValidateChain(chain, trustStore); Console.WriteLine($"Validazione Chain: {(validationResult.IsValid ? "OK" : "ERRORE")}"); Console.WriteLine("\n✓ Intermediate-CA creata con successo!"); } } }
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; // Creazione certificato 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 Creazione Intermediate-CA ==='); WriteLn; res := wvds_sec_crypto_x509_init(); if res <> WVDS_OK then begin WriteLn('ERRORE: Init fallito'); Exit; end; try // ═══════════════════════════════════════════════════════════ // FASE 1: Creare CSR // ═══════════════════════════════════════════════════════════ WriteLn('=== FASE 1: Creazione CSR ==='); WriteLn; // 1. Generare coppia chiavi WriteLn('Generazione coppia chiavi ML-DSA-65...'); intKeyPair := wvds_sec_crypto_x509_keypair_generate_mldsa(65); if intKeyPair = nil then raise Exception.Create('Generazione KeyPair fallita'); // 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. Extensions per 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. Creare CSR WriteLn('Creazione CSR...'); csr := wvds_sec_crypto_x509_csr_create(intDn, intKeyPair, intExt); if csr = nil then raise Exception.Create('Creazione CSR fallita'); // 5. Firmare CSR res := wvds_sec_crypto_x509_csr_sign(csr, intKeyPair); if res <> WVDS_OK then raise Exception.Create('Firma CSR fallita'); // 6. Salvare CSR come 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 salvato: intermediate-ca.csr.pem'); // 7. Salvare chiave privata 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('Chiave privata salvata: intermediate-ca.key.pem'); WriteLn; // ═══════════════════════════════════════════════════════════ // FASE 2: Emettere certificato da Root-CA // ═══════════════════════════════════════════════════════════ WriteLn('=== FASE 2: Emissione certificato ==='); WriteLn; // 8. Caricare Root-CA WriteLn('Caricamento Root-CA...'); rootCert := wvds_sec_crypto_x509_cert_load_pem( PAnsiChar(LoadFileToString('root-ca.crt.pem')) ); if rootCert = nil then raise Exception.Create('Caricamento certificato Root fallito'); 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('Caricamento chiave Root fallito'); // 9. Validare CSR WriteLn('Validazione CSR...'); res := wvds_sec_crypto_x509_csr_verify(csr); if res <> WVDS_OK then raise Exception.Create('Firma CSR non valida'); WriteLn('Firma CSR: OK'); // 10. Extensions per certificato 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. Numero seriale e validità 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 anni ); // 12. Emettere certificato WriteLn('Emissione certificato...'); intCert := wvds_sec_crypto_x509_cert_create_from_csr( csr, rootCert, rootKeyPair, @serial[0], 20, validity, certExt ); if intCert = nil then raise Exception.Create('Creazione certificato fallita'); // 13. Salvare certificato 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('Certificato salvato: intermediate-ca.crt.pem'); WriteLn; // ═══════════════════════════════════════════════════════════ // FASE 3: Creare CA-Chain // ═══════════════════════════════════════════════════════════ WriteLn('=== FASE 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 salvata: ca-chain.pem'); WriteLn; WriteLn('=== Intermediate-CA creata con successo! ==='); finally // Cleanup 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.
Extensions per Intermediate-CA
| Extension | OID | Valore | Critical | Descrizione |
|---|---|---|---|---|
| Basic Constraints | 2.5.29.19 | CA=true, pathLen=0 | Si | Nessuna ulteriore Sub-CA consentita |
| Key Usage | 2.5.29.15 | keyCertSign, cRLSign | Si | Solo firma certificati/CRL |
| Subject Key Identifier | 2.5.29.14 | SHA-256(publicKey) | No | ID univoco chiave |
| Authority Key Identifier | 2.5.29.35 | Root-CA SKI | No | Riferimento a chiave Issuer |
| CRL Distribution Points | 2.5.29.31 | URL(s) | No | Dove la CRL è disponibile |
| Authority Info Access | 1.3.6.1.5.5.7.1.1 | OCSP + caIssuers | No | URL OCSP e URL certificato CA |
| Certificate Policies | 2.5.29.32 | Policy OID(s) | No | Opzionale: Policy di emissione |
| Extended Key Usage | 2.5.29.37 | Opzionale | No | Opzionale: Limitazione a scopo d'uso |
Differenze rispetto a Root-CA
| Aspetto | Root-CA | Intermediate-CA |
|---|---|---|
| Issuer | = Subject (autofirmato) | = Root-CA Subject |
| Firmato da | Propria chiave | Chiave Root-CA |
| pathLength | 1 o 2 | 0 (solo End-Entity) |
| Validità | 15-25 anni | 8-12 anni |
| AKI | Non presente | Root-CA SKI |
| CDP | Opzionale | Obbligatorio |
| AIA | Non presente | OCSP + caIssuers |
| Ubicazione chiave | Offline / HSM | Online (protetta) |
| Utilizzo | Solo firmare Intermediate-CA | Firmare certificati End-Entity |
Avvisi di sicurezza
Protezione chiave Intermediate-CA:
- Salvare chiave privata crittografata (Argon2id + AES-256-GCM)
- Idealmente in HSM o hardware token
- Limitare l'accesso (solo servizio CA)
- Audit-Logging per tutte le operazioni di firma
- Pianificare rotazione chiavi regolare
Best Practices:
- pathLength=0 impedisce ulteriori Sub-CA sotto questa Intermediate-CA
- Intermediate-CA separate per scopi diversi (Server, Client, Code-Signing)
- CDP e AIA impostare sempre per verifica revoca
- Trasferire CSR offline (chiavetta USB) al sistema Root-CA Air-Gapped
- Catena certificati (ca-chain.pem) fornire per deployment semplice
Evitare errori comuni:
- Non creare Intermediate-CA con la stessa chiave di Root
- Non impostare pathLength > 0 se non si desidera Sub-Sub-CA
- Non dimenticare AKI (complica Chain-Building)
- Non dimenticare CDP/AIA (verifica revoca fallisce)
File di output
| File | Tipo | Descrizione |
|---|---|---|
intermediate-ca.csr.pem | PKCS#10 | Certificate Signing Request |
intermediate-ca.key.pem | PKCS#8 (encrypted) | Chiave privata crittografata |
intermediate-ca.crt.pem | X.509 | Certificato Intermediate-CA |
ca-chain.pem | PEM Bundle | Intermediate + Root (per deployment) |
Valori di ritorno
| Codice | Costante | Significato |
|---|---|---|
| 0 | WVDS_OK | Successo |
| 1 | WVDS_ERROR_INVALID_PARAMETER | Parametro non valido |
| 105 | WVDS_ERROR_INVALID_CSR | Formato CSR non valido |
| 202 | WVDS_ERROR_SIGNATURE_INVALID | Firma CSR non valida |
| 208 | WVDS_ERROR_WRONG_PASSWORD | Password chiave Root errata |
Scenari correlati
| Relazione | Scenario | Descrizione |
|---|---|---|
| Prerequisito | 1.1 Creare Root-CA | Root-CA deve esistere |
| Passo successivo | 1.4 Trust Store | Distribuire certificato Root |
| Passo successivo | 1.6 CRL/OCSP | Configurare revoca |
| Poi | 3.1 Certificato Server | Emettere certificati End-Entity |
| Alternativa | 1.3 Gerarchia CA | Più Intermediate-CA |
Riferimenti
« ← 1.1 Root-CA | ▲ Infrastruttura PKI | 1.3 Gerarchia CA → »
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional
Zuletzt geändert: il 30/01/2026 alle 06:49