Scenario 1.1: Creare Root-CA con chiavi PQ

Categoria: Infrastruttura PKI
Complessità: Alta
Prerequisiti: Nessuno (punto di ingresso)
Tempo stimato: 15-30 minuti


Descrizione

Questo scenario descrive la creazione di una Root-CA autofirmata con chiavi Post-Quantum. La Root-CA costituisce l'ancora di fiducia (Trust Anchor) per l'intera gerarchia PKI ed è l'elemento più critico per la sicurezza dell'infrastruttura.

Cosa viene creato:

  • Coppia di chiavi ML-DSA-65 (sicura post-quantum)
  • Certificato Root X.509 v3 autofirmato
  • Chiave privata crittografata (PKCS#8 con Argon2id)

Casi d'uso:

  • Costruzione di una nuova PKI Enterprise con capacità PQ
  • Migrazione di PKI esistente ad algoritmi Post-Quantum
  • Ambiente di test per certificati PQ
  • PKI isolata per applicazioni speciali (IoT, Code-Signing)

Diagramma di flusso

┌─────────────────────────────────────────────────────────────────┐
│                    CREAZIONE ROOT-CA                            │
└─────────────────────────────────────────────────────────────────┘

     ┌──────────────┐
     │ 1. Init      │
     │ Libreria     │
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 2. KeyPair   │ ──────► ML-DSA-65 (FIPS 204)
     │ generare     │         ~4KB Chiave pubblica
     └──────┬───────┘         ~2KB Chiave privata
            │
            ▼
     ┌──────────────┐
     │ 3. DN        │ ──────► CN=WvdS Root CA
     │ creare       │         O=DATECpro GmbH
     └──────┬───────┘         C=DE
            │
            ▼
     ┌──────────────┐
     │ 4. Serial    │ ──────► 20 Bytes casuali (160 bit)
     │ generare     │
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 5. Validity  │ ──────► notBefore: adesso
     │ definire     │         notAfter: +20 anni
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 6. Extensions│ ──────► BasicConstraints: CA=true, pathLen=1
     │ impostare    │         KeyUsage: keyCertSign, cRLSign
     └──────┬───────┘         SKI: SHA-256(publicKey)
            │
            ▼
     ┌──────────────┐
     │ 7. Certificato│ ──────► Subject = Issuer (autofirmato)
     │ creare       │         Firma con ML-DSA-65
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 8. Export    │ ──────► root-ca.crt.pem (Certificato)
     │ PEM          │         root-ca.key.pem (crittografato)
     └──────┬───────┘
            │
            ▼
     ┌──────────────┐
     │ 9. Cleanup   │ ──────► Rilasciare handle
     │              │         Azzerare secret
     └──────────────┘

Funzioni coinvolte

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
2a wvds_sec_crypto_x509_keypair_self_test() ml-dsa Autotest (sign/verify)
3a wvds_sec_crypto_x509_dn_create() x509-cert Creare handle DN
3b wvds_sec_crypto_x509_dn_add_component() x509-cert, der Aggiungere CN, O, C
4 wvds_sec_crypto_x509_serial_generate() rand Numero seriale 160-bit
5 wvds_sec_crypto_x509_validity_create() x509-cert Periodo di validità
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 Creare certificato Root
8a wvds_sec_crypto_x509_cert_to_pem() pem-rfc7468 Certificato come PEM
8b wvds_sec_crypto_x509_keypair_to_pem_encrypted() argon2, aes-gcm Chiave crittografata
9a wvds_sec_crypto_x509_free_*() std::alloc Rilasciare handle
9b wvds_sec_crypto_x509_zeroize_keypair() zeroize Cancellare secret

Albero delle funzioni

wvds_sec_crypto_x509_init()
│
├── wvds_sec_crypto_x509_keypair_generate_mldsa(level: u8)  → *mut KeyPairHandle
│   │
│   ├── // Scelta parametri
│   │   ├── [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)
│   │
│   ├── // Autotest (requisito FIPS)
│   │   ├── test_msg = [0x00..0x20]  // 32 Bytes dati di test
│   │   ├── signature = signing_key.sign(&test_msg)
│   │   └── assert!(verifying_key.verify(&test_msg, &signature).is_ok())
│   │
│   └── // Creare handle
│       └── Box::into_raw(Box::new(KeyPairHandle {
│               algorithm: ML_DSA_65,
│               signing_key,
│               verifying_key
│           }))
│
├── wvds_sec_crypto_x509_dn_create()  → *mut DnHandle
│   └── x509_cert::name::Name::default()
│
├── wvds_sec_crypto_x509_dn_add_component(dn, oid, value)  → i32
│   │
│   ├── [OID_CN = "2.5.4.3"]
│   │   └── dn.0.push(RelativeDistinguishedName::from(
│   │           AttributeTypeAndValue { oid: OID_CN, value: "WvdS Root CA" }
│   │       ))
│   │
│   ├── [OID_O = "2.5.4.10"]
│   │   └── dn.0.push(..., value: "DATECpro GmbH")
│   │
│   └── [OID_C = "2.5.4.6"]
│       └── dn.0.push(..., value: "DE")
│
├── wvds_sec_crypto_x509_serial_generate(out: *mut u8, len: usize)  → i32
│   │
│   ├── // RFC 5280: max 20 Bytes, positivo
│   │   └── rand::rngs::OsRng.fill_bytes(&mut serial[0..len])
│   │
│   └── // Impostare bit più alto a 0 (positivo)
│       └── 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 per date >= 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)  // solo 1 livello Intermediate
│   │   }
│   │
│   └── ext.add(Extension {
│           extn_id: OID_BASIC_CONSTRAINTS,
│           critical: true,  // DEVE essere critical per CA
│           extn_value: der::Encode::to_der(&bc)
│       })
│
├── wvds_sec_crypto_x509_ext_set_key_usage(ext, flags: u16)  → i32
│   │
│   ├── // Per 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,  // DOVREBBE essere 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
│   │
│   ├── // Costruire 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(),      // autofirmato: issuer = subject
│   │           validity: validity.clone(),
│   │           subject: subject.clone(),
│   │           subject_public_key_info: keypair.to_spki(),
│   │           extensions: Some(extensions.clone())
│   │       }
│   │
│   ├── // Codificare TBS-Certificate in DER
│   │   └── tbs_der = der::Encode::to_der(&tbs)
│   │
│   ├── // Firmare con ML-DSA-65
│   │   └── signature = ml_dsa::ml_dsa_65::SigningKey::sign(&tbs_der)
│   │       │
│   │       └── // Firma deterministica (FIPS 204)
│   │           // Lunghezza firma: 3293 Bytes
│   │
│   └── // Assemblare 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)
│       │
│       └── // Output esempio:
│           // -----BEGIN CERTIFICATE-----
│           // MIIxxxxxx...
│           // -----END CERTIFICATE-----
│
├── wvds_sec_crypto_x509_keypair_to_pem_encrypted(
│       keypair, password, kdf_algorithm, out, out_len
│   )  → i32
│   │
│   ├── // Chiave privata come PKCS#8 DER
│   │   └── private_key_der = keypair.signing_key.to_pkcs8_der()
│   │
│   ├── // Generare Salt e Nonce
│   │   ├── salt = rand::OsRng.gen::<[u8; 16]>()
│   │   └── nonce = rand::OsRng.gen::<[u8; 12]>()
│   │
│   ├── // Derivare Key Encryption Key
│   │   └── [ARGON2ID]
│   │       └── argon2::Argon2::new(
│   │               Algorithm::Argon2id,
│   │               Version::V0x13,
│   │               Params::new(65536, 3, 4, Some(32))  // 64MB, 3 Iter, 4 Lanes
│   │           ).hash_password_into(password.as_bytes(), &salt, &mut kek)
│   │
│   ├── // Crittografare chiave privata
│   │   └── encrypted = aes_gcm::Aes256Gcm::new(&kek)
│   │           .encrypt(&nonce, private_key_der.as_ref())
│   │
│   ├── // Creare EncryptedPrivateKeyInfo (PKCS#8)
│   │   └── epki = pkcs8::EncryptedPrivateKeyInfo {
│   │           encryption_algorithm: ...,
│   │           encrypted_data: encrypted
│   │       }
│   │
│   ├── // Codificare come PEM
│   │   └── pem_rfc7468::encode_string("ENCRYPTED PRIVATE KEY", &epki_der)
│   │
│   └── // Azzerare KEK
│       └── zeroize::Zeroize::zeroize(&mut kek)
│
└── // Cleanup
    │
    ├── wvds_sec_crypto_x509_free_cert(cert)
    ├── wvds_sec_crypto_x509_free_keypair(keypair)
    │   └── // Zeroize automatico via Drop
    ├── wvds_sec_crypto_x509_free_dn(dn)
    ├── wvds_sec_crypto_x509_free_validity(validity)
    ├── wvds_sec_crypto_x509_free_ext(ext)
    └── wvds_sec_crypto_x509_shutdown()

Esempi di codice

C# (.NET Wrapper)

using System;
using System.IO;
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
namespace RootCaExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // Password per chiave privata (in produzione: inserire in modo sicuro!)
            string keyPassword = "MyStr0ng!RootCA#Password2024";
 
            // 1. Inizializzare contesto
            using var context = PqCryptoContext.Initialize();
 
            // 2. Generare coppia chiavi ML-DSA-65
            Console.WriteLine("Generazione coppia chiavi ML-DSA-65...");
            using var keyPair = context.GenerateKeyPair(PqAlgorithm.MlDsa65);
 
            // Eseguire autotest
            if (!keyPair.SelfTest())
                throw new CryptographicException("KeyPair self-test failed!");
 
            Console.WriteLine($"  Chiave pubblica:  {keyPair.PublicKeySize} Bytes");
            Console.WriteLine($"  Chiave privata: {keyPair.PrivateKeySize} Bytes");
 
            // 3. Creare 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. Periodo di validità (20 anni per Root-CA)
            var validity = new CertificateValidity(
                notBefore: DateTime.UtcNow,
                notAfter: DateTime.UtcNow.AddYears(20)
            );
 
            // 5. Extensions per Root-CA
            var extensions = new X509ExtensionsBuilder()
                // BasicConstraints: CA=true, max 1 livello Intermediate
                .AddBasicConstraints(isCa: true, pathLengthConstraint: 1, critical: true)
                // KeyUsage: solo firma certificati e CRL
                .AddKeyUsage(
                    KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign,
                    critical: true
                )
                // Subject Key Identifier per riferimento AKI successivo
                .AddSubjectKeyIdentifier(keyPair)
                .Build();
 
            // 6. Creare certificato Root (autofirmato)
            Console.WriteLine("Creazione certificato Root autofirmato...");
            using var rootCert = context.CreateRootCertificate(
                keyPair: keyPair,
                subject: subjectDn,
                validity: validity,
                extensions: extensions
            );
 
            // 7. Visualizzare informazioni certificato
            Console.WriteLine("\n=== CERTIFICATO ROOT-CA ===");
            Console.WriteLine($"Subject:        {rootCert.Subject}");
            Console.WriteLine($"Issuer:         {rootCert.Issuer}");
            Console.WriteLine($"Serial:         {rootCert.SerialNumber}");
            Console.WriteLine($"Not Before:     {rootCert.NotBefore:yyyy-MM-dd HH:mm:ss} UTC");
            Console.WriteLine($"Not After:      {rootCert.NotAfter:yyyy-MM-dd HH:mm:ss} UTC");
            Console.WriteLine($"Algorithm:      {rootCert.SignatureAlgorithm}");
            Console.WriteLine($"Thumbprint:     {rootCert.Thumbprint}");
            Console.WriteLine($"Is CA:          {rootCert.IsCertificateAuthority}");
            Console.WriteLine($"Path Length:    {rootCert.PathLengthConstraint}");
 
            // 8. Salvare come file PEM
            string certPath = "root-ca.crt.pem";
            string keyPath = "root-ca.key.pem";
 
            // Certificato (pubblico)
            File.WriteAllText(certPath, rootCert.ExportToPem());
            Console.WriteLine($"\nCertificato salvato: {certPath}");
 
            // Chiave privata (crittografata con Argon2id)
            File.WriteAllText(keyPath, keyPair.ExportToEncryptedPem(
                password: keyPassword,
                kdfAlgorithm: KeyDerivationAlgorithm.Argon2id
            ));
            Console.WriteLine($"Chiave privata salvata: {keyPath} (crittografata)");
 
            // 9. Validazione: ricaricare certificato e verificare
            Console.WriteLine("\n=== VALIDAZIONE ===");
            using var loadedCert = context.LoadCertificateFromPem(File.ReadAllText(certPath));
            using var loadedKey = context.LoadKeyPairFromEncryptedPem(
                File.ReadAllText(keyPath),
                keyPassword
            );
 
            // Verificare autofirma
            bool signatureValid = loadedCert.VerifySignature(loadedCert);  // autofirmato
            Console.WriteLine($"Autofirma valida: {signatureValid}");
 
            // Verificare corrispondenza coppia chiavi
            bool keyMatch = loadedCert.PublicKeyMatches(loadedKey);
            Console.WriteLine($"Match chiave pubblica:      {keyMatch}");
 
            Console.WriteLine("\n✓ Root-CA creata con successo!");
        }
    }
}

Delphi (FFI)

program CreateRootCA;
 
{$APPTYPE CONSOLE}
 
uses
  SysUtils, DateUtils,
  WvdS.PqCrypto.FFI;  // Unit FFI con dichiarazioni
 
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 Creazione Root-CA ===');
  WriteLn;
 
  // 1. Inizializzare libreria
  res := wvds_sec_crypto_x509_init();
  if res <> WVDS_OK then
  begin
    WriteLn('ERRORE: Init fallito (', res, ')');
    Exit;
  end;
 
  try
    // 2. Generare coppia chiavi ML-DSA-65
    WriteLn('Generazione coppia chiavi ML-DSA-65...');
    keypair := wvds_sec_crypto_x509_keypair_generate_mldsa(65);
    if keypair = nil then
      raise Exception.Create('Generazione KeyPair fallita');
 
    // Autotest
    res := wvds_sec_crypto_x509_keypair_self_test(keypair);
    if res <> WVDS_OK then
      raise Exception.Create('Autotest KeyPair fallito');
    WriteLn('  Autotest: OK');
 
    // 3. Creare Distinguished Name
    WriteLn('Creazione Distinguished Name...');
    dn := wvds_sec_crypto_x509_dn_create();
    if dn = nil then
      raise Exception.Create('Creazione DN fallita');
 
    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. Generare numero seriale (20 Bytes = 160 Bit)
    WriteLn('Generazione numero seriale...');
    res := wvds_sec_crypto_x509_serial_generate(@serial[0], 20);
    if res <> WVDS_OK then
      raise Exception.Create('Generazione Serial fallita');
 
    // 5. Validità: 20 anni
    WriteLn('Impostazione periodo di validità (20 anni)...');
    validity := wvds_sec_crypto_x509_validity_create(
      DateTimeToUnix(Now, False),                      // not_before: adesso
      DateTimeToUnix(IncYear(Now, 20), False)          // not_after: +20 anni
    );
    if validity = nil then
      raise Exception.Create('Creazione Validity fallita');
 
    // 6. Creare Extensions
    WriteLn('Impostazione Extensions...');
    ext := wvds_sec_crypto_x509_ext_create();
    if ext = nil then
      raise Exception.Create('Creazione Extension fallita');
 
    // 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 fallito');
 
    // 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 fallito');
 
    // Subject Key Identifier
    res := wvds_sec_crypto_x509_ext_set_ski_from_keypair(ext, keypair);
    if res <> WVDS_OK then
      raise Exception.Create('SKI fallito');
 
    // 7. Creare certificato Root (autofirmato)
    WriteLn('Creazione certificato Root autofirmato...');
    cert := wvds_sec_crypto_x509_cert_create_root(
      keypair,          // Coppia chiavi
      dn,               // Subject (= Issuer per Root)
      @serial[0], 20,   // Numero seriale
      validity,         // Validità
      ext               // Extensions
    );
    if cert = nil then
      raise Exception.Create('Creazione certificato fallita');
 
    // 8. Salvare come PEM
    WriteLn;
    WriteLn('Salvataggio file...');
 
    // Certificato
    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('Export certificato fallito');
 
    with TFileStream.Create('root-ca.crt.pem', fmCreate) do
    try
      Write(pem_buf[0], pem_len);
    finally
      Free;
    end;
    WriteLn('  root-ca.crt.pem salvato');
 
    // Chiave privata (crittografata)
    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('Export chiave fallito');
 
    with TFileStream.Create('root-ca.key.pem', fmCreate) do
    try
      Write(pem_buf[0], pem_len);
    finally
      Free;
    end;
    WriteLn('  root-ca.key.pem salvato (crittografato)');
 
    WriteLn;
    WriteLn('=== Root-CA creata con successo! ===');
 
  finally
    // 9. Cleanup
    if cert <> nil then wvds_sec_crypto_x509_free_cert(cert);
    if keypair <> nil then wvds_sec_crypto_x509_free_keypair(keypair);
    if dn <> nil then wvds_sec_crypto_x509_free_dn(dn);
    if validity <> nil then wvds_sec_crypto_x509_free_validity(validity);
    if ext <> nil then wvds_sec_crypto_x509_free_ext(ext);
    wvds_sec_crypto_x509_shutdown();
  end;
end.

Parametri

wvds_sec_crypto_x509_keypair_generate_mldsa

Parametro Tipo Descrizione Valori validi
level u8 Livello di sicurezza ML-DSA 44, 65, 87
Livello Sicurezza NIST Chiave pubblica Chiave privata Firma
44 Livello 2 (~128-bit) 1.312 Bytes 2.560 Bytes 2.420 Bytes
65 Livello 3 (~192-bit) 1.952 Bytes 4.032 Bytes 3.293 Bytes
87 Livello 5 (~256-bit) 2.592 Bytes 4.896 Bytes 4.595 Bytes

wvds_sec_crypto_x509_dn_add_component

Parametro Tipo Descrizione Esempio
dn *mut DnHandle Handle DN
oid *const c_char OID come stringa „2.5.4.3“
value *const c_char Valore UTF-8 „WvdS Root CA“
OID Costante Descrizione Valore esempio
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 caratteri) 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

Parametro Tipo Descrizione Valore Root-CA
ext *mut ExtHandle Handle Extension
ca bool È certificato CA true
path_len i32 Lunghezza max. percorso (-1 = illimitato) 1 o 2

wvds_sec_crypto_x509_ext_set_key_usage

Flag Bit Valore Descrizione
digitalSignature 0 0x0080 Firme digitali
nonRepudiation 1 0x0040 Non ripudiabilità
keyEncipherment 2 0x0020 Crittografia chiavi
dataEncipherment 3 0x0010 Crittografia dati
keyAgreement 4 0x0008 Accordo chiavi
keyCertSign 5 0x0004 Firma certificati
cRLSign 6 0x0002 Firma CRL
encipherOnly 7 0x0001 Solo crittografia

Per Root-CA: flags = 0x0006 (keyCertSign + cRLSign)


Valori di ritorno

Codice Costante Significato
0 WVDS_OK Successo
1 WVDS_ERROR_INVALID_PARAMETER Parametro non valido (es. level diverso da 44/65/87)
2 WVDS_ERROR_OUT_OF_MEMORY Allocazione memoria fallita
3 WVDS_ERROR_NOT_INITIALIZED init() non chiamato
200 WVDS_ERROR_KEY_GENERATION_FAILED Generazione chiave fallita
201 WVDS_ERROR_SIGNATURE_FAILED Firma fallita
210 WVDS_ERROR_KEYPAIR_SELF_TEST_FAILED Autotest fallito

Lista completa: Codici errore


File di output

root-ca.crt.pem

-----BEGIN CERTIFICATE-----
MIIHxjCCBiagAwIBAgIUP7J2kM9x... (DER codificato Base64)
...
-----END CERTIFICATE-----
Campo Valore
Version 3 (0x02)
Serial 20 Bytes casuali
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 anni
Public Key ML-DSA-65 (~1.952 Bytes)
Extensions BasicConstraints, KeyUsage, SKI
Signature ML-DSA-65 (~3.293 Bytes)

root-ca.key.pem

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIHbTBXBgkqhkiG9w0BBQ0w... (PKCS#8 EncryptedPrivateKeyInfo)
...
-----END ENCRYPTED PRIVATE KEY-----
Campo Valore
Formato PKCS#8 EncryptedPrivateKeyInfo
KDF Argon2id (64MB, 3 iterazioni, 4 Lanes)
Cipher AES-256-GCM
Key Size ~4.032 Bytes (chiave privata ML-DSA-65)

Avvisi di sicurezza

CRITICO - Chiave privata Root-CA:

La chiave privata della Root-CA è l'elemento più critico per la sicurezza dell'intera PKI. La compromissione significa perdita completa della fiducia!

  • Mai generare o archiviare su sistemi connessi in rete
  • Mai archiviare non crittografata
  • Mai trasmettere via e-mail o canali non sicuri

Misure di protezione raccomandate:

  • Sistema Air-Gapped: Operazioni Root-CA su computer isolato senza rete
  • HSM: Hardware Security Module per archiviazione chiavi (es. YubiHSM, Thales Luna)
  • Crittografia: Almeno AES-256 con password forte (>=20 caratteri)
  • Sicurezza fisica: Chiavetta USB crittografata in cassaforte o cassetta di sicurezza
  • Backup: Almeno 2 copie in sedi separate
  • Key Ceremony: Processo documentato con testimoni per tutte le operazioni Root-CA
  • Audit-Log: Registrare tutti gli accessi

Best Practices:

  • ML-DSA-65 offre buon rapporto sicurezza/prestazioni per Root-CA
  • pathLength=1 limita la gerarchia a Root → Intermediate → End-Entity
  • 20 anni di validità è comune per Root-CA (max. 25 anni raccomandati)
  • Impostare SKI consente riferimento AKI successivo in certificati Intermediate
  • Autotest dopo generazione assicura implementazione corretta

Errori comuni

Problema Causa Soluzione
KEY_GENERATION_FAILED Entropia insufficiente Verificare sorgente casuale OS, /dev/urandom disponibile?
KEYPAIR_SELF_TEST_FAILED Implementazione difettosa Verificare versione libreria, ricompilare
Certificato non valido DN vuoto Impostare almeno CN
Chiave non leggibile Password errata Verificare password, encoding (UTF-8)
Errore pathLength Valore < -1 -1 per illimitato, 0, 1, 2, … per limite
NOT_INITIALIZED init() dimenticato Chiamare prima wvds_sec_crypto_x509_init()
Memory leak Handle non rilasciati Chiamare tutte le funzioni free_*()
PEM troppo grande Buffer troppo piccolo Richiedere dimensione prima (out_len = 0)

Scenari correlati

Relazione Scenario Descrizione
Passo successivo 1.2 Intermediate-CA Firmare CA subordinata da Root
Poi 1.4 Trust Store Distribuire certificato Root
Poi 1.6 CRL/OCSP Configurare servizi di revoca
Alternativa 11.1 Generare chiavi Solo chiavi, nessun certificato
Correlato 11.2 Archiviare chiavi Ulteriori opzioni di archiviazione

Riferimenti

Documentazione API

Concetti

Sicurezza

Tabelle di riferimento

Standard esterni

Zuletzt geändert: il 30/01/2026 alle 06:46