====== Scenario 1.1: Creare Root-CA con chiavi PQ ======
**Categoria:** [[.:start|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:// [[it:int:pqcrypt:referenz:error_codes_tabelle|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** | [[.:intermediate_ca_erstellen|1.2 Intermediate-CA]] | Firmare CA subordinata da Root |
| **Poi** | [[.:trust_store_konfigurieren|1.4 Trust Store]] | Distribuire certificato Root |
| **Poi** | [[.:crl_ocsp_infrastruktur|1.6 CRL/OCSP]] | Configurare servizi di revoca |
| **Alternativa** | [[it:int:pqcrypt:szenarien:schluessel:generierung|11.1 Generare chiavi]] | Solo chiavi, nessun certificato |
| **Correlato** | [[it:int:pqcrypt:szenarien:schluessel:speicherung|11.2 Archiviare chiavi]] | Ulteriori opzioni di archiviazione |
----
===== Riferimenti =====
=== Documentazione API ===
* [[it:int:pqcrypt:api:module:init|Modulo: init]]
* [[it:int:pqcrypt:api:module:keypair|Modulo: keypair]]
* [[it:int:pqcrypt:api:module:dn|Modulo: dn]]
* [[it:int:pqcrypt:api:module:cert|Modulo: cert]]
* [[it:int:pqcrypt:api:module:ext|Modulo: ext]]
* [[it:int:pqcrypt:api:module:free|Modulo: free]]
=== Concetti ===
* [[it:int:pqcrypt:konzepte:fips_204_ml_dsa|ML-DSA (FIPS 204)]]
* [[it:int:pqcrypt:konzepte:pki_grundlagen|Fondamenti PKI]]
* [[it:int:pqcrypt:konzepte:x509_erweiterungen|Estensioni X.509]]
=== Sicurezza ===
* [[it:int:pqcrypt:sicherheit:schluessellaengen|Lunghezze chiavi raccomandate]]
* [[it:int:pqcrypt:sicherheit:secure_memory|Gestione memoria sicura]]
=== Tabelle di riferimento ===
* [[it:int:pqcrypt:referenz:oid_tabelle|Tabella OID]]
* [[it:int:pqcrypt:referenz:error_codes_tabelle|Codici errore]]
* [[it:int:pqcrypt:referenz:schluesselgroessen|Dimensioni chiavi]]
* [[it:int:pqcrypt:referenz:signaturgroessen|Dimensioni firme]]
=== Standard esterni ===
* [[https://csrc.nist.gov/pubs/fips/204/final|NIST FIPS 204: ML-DSA]]
* [[https://www.rfc-editor.org/rfc/rfc5280|RFC 5280: X.509 PKI]]
* [[https://www.rfc-editor.org/rfc/rfc5958|RFC 5958: PKCS#8]]
* [[https://datatracker.ietf.org/doc/draft-ietf-lamps-dilithium-certificates/|IETF: ML-DSA in X.509]]
----
<< [[.:start|← Infrastruttura PKI]] | [[it:int:pqcrypt:szenarien:start|▲ Scenari]] | [[.:intermediate_ca_erstellen|1.2 Intermediate-CA →]] >>
{{tag>scenario pki root-ca ml-dsa-65 autofirmato keypair certificato fips-204}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//
~~NOTOC~~