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