====== Scenarij 1.1: Kreiranje Root-CA s PQ ključevima ======
**Kategorija:** [[.:start|PKI infrastruktura]] \\
**Složenost:** ⭐⭐⭐⭐ (Visoka) \\
**Preduvjeti:** Nema (ulazna točka) \\
**Procijenjeno vrijeme:** 15-30 minuta
----
===== Opis =====
Ovaj scenarij opisuje kreiranje **samopotpisanog Root-CA** s Post-Quantum ključevima. Root-CA čini **sidrište povjerenja (Trust Anchor)** za cijelu PKI hijerarhiju i najkritičniji je sigurnosni element infrastrukture.
**Što se kreira:**
* ML-DSA-65 par ključeva (Post-Quantum siguran)
* Samopotpisani X.509 v3 Root certifikat
* Šifrirani privatni ključ (PKCS#8 s Argon2id)
**Slučajevi uporabe:**
* Izgradnja nove PQ-spremne Enterprise PKI
* Migracija postojeće PKI na Post-Quantum algoritme
* Testno okruženje za PQ certifikate
* Izolirana PKI za posebne primjene (IoT, Code-Signing)
----
===== Dijagram tijeka =====
┌─────────────────────────────────────────────────────────────────┐
│ KREIRANJE ROOT-CA │
└─────────────────────────────────────────────────────────────────┘
┌──────────────┐
│ 1. Init │
│ Biblioteka │
└──────┬───────┘
│
▼
┌──────────────┐
│ 2. KeyPair │ ──────► ML-DSA-65 (FIPS 204)
│ generiranje │ ~4KB javni ključ
└──────┬───────┘ ~2KB privatni ključ
│
▼
┌──────────────┐
│ 3. DN │ ──────► CN=WvdS Root CA
│ kreiranje │ O=DATECpro GmbH
└──────┬───────┘ C=DE
│
▼
┌──────────────┐
│ 4. Serial │ ──────► 20 bajtova slučajnih (160 bit)
│ generiranje │
└──────┬───────┘
│
▼
┌──────────────┐
│ 5. Validity │ ──────► notBefore: sada
│ postavljanje │ notAfter: +20 godina
└──────┬───────┘
│
▼
┌──────────────┐
│ 6. Extensions│ ──────► BasicConstraints: CA=true, pathLen=1
│ postavljanje │ KeyUsage: keyCertSign, cRLSign
└──────┬───────┘ SKI: SHA-256(publicKey)
│
▼
┌──────────────┐
│ 7. Certifikat│ ──────► Subject = Issuer (samopotpisan)
│ kreiranje │ Potpis s ML-DSA-65
└──────┬───────┘
│
▼
┌──────────────┐
│ 8. Export │ ──────► root-ca.crt.pem (certifikat)
│ PEM │ root-ca.key.pem (šifrirano)
└──────┬───────┘
│
▼
┌──────────────┐
│ 9. Cleanup │ ──────► Oslobađanje handle-a
│ │ Brisanje tajni (zeroize)
└──────────────┘
----
===== Uključene funkcije =====
^ Korak ^ FFI funkcija ^ Rust Crate ^ Opis ^
| 1 | ''wvds_sec_crypto_x509_init()'' | ''std::sync'' | Inicijalizacija biblioteke |
| 2 | ''wvds_sec_crypto_x509_keypair_generate_mldsa(65)'' | ''ml-dsa'' | ML-DSA-65 par ključeva |
| 2a | ''wvds_sec_crypto_x509_keypair_self_test()'' | ''ml-dsa'' | Samotest (sign/verify) |
| 3a | ''wvds_sec_crypto_x509_dn_create()'' | ''x509-cert'' | Kreiranje DN handle-a |
| 3b | ''wvds_sec_crypto_x509_dn_add_component()'' | ''x509-cert'', ''der'' | Dodavanje CN, O, C |
| 4 | ''wvds_sec_crypto_x509_serial_generate()'' | ''rand'' | 160-bitni serijski broj |
| 5 | ''wvds_sec_crypto_x509_validity_create()'' | ''x509-cert'' | Razdoblje valjanosti |
| 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'' | Kreiranje Root certifikata |
| 8a | ''wvds_sec_crypto_x509_cert_to_pem()'' | ''pem-rfc7468'' | Certifikat kao PEM |
| 8b | ''wvds_sec_crypto_x509_keypair_to_pem_encrypted()'' | ''argon2'', ''aes-gcm'' | Šifrirani ključ |
| 9a | ''wvds_sec_crypto_x509_free_*()'' | ''std::alloc'' | Oslobađanje handle-a |
| 9b | ''wvds_sec_crypto_x509_zeroize_keypair()'' | ''zeroize'' | Brisanje tajni |
----
===== Stablo funkcija =====
wvds_sec_crypto_x509_init()
│
├── wvds_sec_crypto_x509_keypair_generate_mldsa(level: u8) → *mut KeyPairHandle
│ │
│ ├── // Odabir parametara
│ │ ├── [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)
│ │
│ ├── // Samotest (FIPS zahtjev)
│ │ ├── test_msg = [0x00..0x20] // 32 bajta testnih podataka
│ │ ├── signature = signing_key.sign(&test_msg)
│ │ └── assert!(verifying_key.verify(&test_msg, &signature).is_ok())
│ │
│ └── // Kreiranje handle-a
│ └── 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 bajtova, pozitivan
│ │ └── rand::rngs::OsRng.fill_bytes(&mut serial[0..len])
│ │
│ └── // Najviši bit na 0 (pozitivan)
│ └── 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 za datume >= 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) // samo 1 Intermediate razina
│ │ }
│ │
│ └── ext.add(Extension {
│ extn_id: OID_BASIC_CONSTRAINTS,
│ critical: true, // MORA biti critical za CA
│ extn_value: der::Encode::to_der(&bc)
│ })
│
├── wvds_sec_crypto_x509_ext_set_key_usage(ext, flags: u16) → i32
│ │
│ ├── // Za 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, // TREBALO BI biti 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
│ │
│ ├── // Izgradnja 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(), // samopotpisan: issuer = subject
│ │ validity: validity.clone(),
│ │ subject: subject.clone(),
│ │ subject_public_key_info: keypair.to_spki(),
│ │ extensions: Some(extensions.clone())
│ │ }
│ │
│ ├── // DER kodiranje TBS-Certificate
│ │ └── tbs_der = der::Encode::to_der(&tbs)
│ │
│ ├── // Potpisivanje s ML-DSA-65
│ │ └── signature = ml_dsa::ml_dsa_65::SigningKey::sign(&tbs_der)
│ │ │
│ │ └── // Deterministički potpis (FIPS 204)
│ │ // Duljina potpisa: 3293 bajta
│ │
│ └── // Sastavljanje 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)
│ │
│ └── // Primjer izlaza:
│ // -----BEGIN CERTIFICATE-----
│ // MIIxxxxxx...
│ // -----END CERTIFICATE-----
│
├── wvds_sec_crypto_x509_keypair_to_pem_encrypted(
│ keypair, password, kdf_algorithm, out, out_len
│ ) → i32
│ │
│ ├── // Privatni ključ kao PKCS#8 DER
│ │ └── private_key_der = keypair.signing_key.to_pkcs8_der()
│ │
│ ├── // Generiranje salta i nonce-a
│ │ ├── salt = rand::OsRng.gen::<[u8; 16]>()
│ │ └── nonce = rand::OsRng.gen::<[u8; 12]>()
│ │
│ ├── // Derivacija Key Encryption Key-a
│ │ └── [ARGON2ID]
│ │ └── argon2::Argon2::new(
│ │ Algorithm::Argon2id,
│ │ Version::V0x13,
│ │ Params::new(65536, 3, 4, Some(32)) // 64MB, 3 iter., 4 trake
│ │ ).hash_password_into(password.as_bytes(), &salt, &mut kek)
│ │
│ ├── // Šifriranje privatnog ključa
│ │ └── encrypted = aes_gcm::Aes256Gcm::new(&kek)
│ │ .encrypt(&nonce, private_key_der.as_ref())
│ │
│ ├── // Kreiranje EncryptedPrivateKeyInfo (PKCS#8)
│ │ └── epki = pkcs8::EncryptedPrivateKeyInfo {
│ │ encryption_algorithm: ...,
│ │ encrypted_data: encrypted
│ │ }
│ │
│ ├── // PEM kodiranje
│ │ └── pem_rfc7468::encode_string("ENCRYPTED PRIVATE KEY", &epki_der)
│ │
│ └── // KEK brisanje
│ └── zeroize::Zeroize::zeroize(&mut kek)
│
└── // Čišćenje
│
├── wvds_sec_crypto_x509_free_cert(cert)
├── wvds_sec_crypto_x509_free_keypair(keypair)
│ └── // Automatski Zeroize putem 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()
----
===== Primjeri koda =====
=== C# (.NET Wrapper) ===
using System;
using System.IO;
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
namespace RootCaExample
{
class Program
{
static void Main(string[] args)
{
// Lozinka za privatni ključ (u produkciji: sigurno unijeti!)
string keyPassword = "MyStr0ng!RootCA#Password2024";
// 1. Inicijalizacija konteksta
using var context = PqCryptoContext.Initialize();
// 2. Generiranje ML-DSA-65 para ključeva
Console.WriteLine("Generiram ML-DSA-65 par ključeva...");
using var keyPair = context.GenerateKeyPair(PqAlgorithm.MlDsa65);
// Izvršavanje samotesta
if (!keyPair.SelfTest())
throw new CryptographicException("KeyPair self-test failed!");
Console.WriteLine($" Javni ključ: {keyPair.PublicKeySize} bajtova");
Console.WriteLine($" Privatni ključ: {keyPair.PrivateKeySize} bajtova");
// 3. Kreiranje 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. Razdoblje valjanosti (20 godina za Root-CA)
var validity = new CertificateValidity(
notBefore: DateTime.UtcNow,
notAfter: DateTime.UtcNow.AddYears(20)
);
// 5. Ekstenzije za Root-CA
var extensions = new X509ExtensionsBuilder()
// BasicConstraints: CA=true, max 1 Intermediate razina
.AddBasicConstraints(isCa: true, pathLengthConstraint: 1, critical: true)
// KeyUsage: samo potpisivanje certifikata i CRL-a
.AddKeyUsage(
KeyUsageFlags.KeyCertSign | KeyUsageFlags.CrlSign,
critical: true
)
// Subject Key Identifier za kasniju AKI referencu
.AddSubjectKeyIdentifier(keyPair)
.Build();
// 6. Kreiranje Root certifikata (samopotpisan)
Console.WriteLine("Kreiram samopotpisani Root certifikat...");
using var rootCert = context.CreateRootCertificate(
keyPair: keyPair,
subject: subjectDn,
validity: validity,
extensions: extensions
);
// 7. Ispis informacija o certifikatu
Console.WriteLine("\n=== ROOT-CA CERTIFIKAT ===");
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($"Algoritam: {rootCert.SignatureAlgorithm}");
Console.WriteLine($"Thumbprint: {rootCert.Thumbprint}");
Console.WriteLine($"Is CA: {rootCert.IsCertificateAuthority}");
Console.WriteLine($"Path Length: {rootCert.PathLengthConstraint}");
// 8. Spremanje kao PEM datoteke
string certPath = "root-ca.crt.pem";
string keyPath = "root-ca.key.pem";
// Certifikat (javni)
File.WriteAllText(certPath, rootCert.ExportToPem());
Console.WriteLine($"\nCertifikat spremljen: {certPath}");
// Privatni ključ (šifriran s Argon2id)
File.WriteAllText(keyPath, keyPair.ExportToEncryptedPem(
password: keyPassword,
kdfAlgorithm: KeyDerivationAlgorithm.Argon2id
));
Console.WriteLine($"Privatni ključ spremljen: {keyPath} (šifrirano)");
// 9. Validacija: Ponovno učitavanje certifikata i provjera
Console.WriteLine("\n=== VALIDACIJA ===");
using var loadedCert = context.LoadCertificateFromPem(File.ReadAllText(certPath));
using var loadedKey = context.LoadKeyPairFromEncryptedPem(
File.ReadAllText(keyPath),
keyPassword
);
// Verifikacija samopotpisa
bool signatureValid = loadedCert.VerifySignature(loadedCert); // self-signed
Console.WriteLine($"Samopotpis valjan: {signatureValid}");
// Provjera pripadnosti para ključeva
bool keyMatch = loadedCert.PublicKeyMatches(loadedKey);
Console.WriteLine($"Public Key Match: {keyMatch}");
Console.WriteLine("\n✓ Root-CA uspješno kreiran!");
}
}
}
=== Delphi (FFI) ===
program CreateRootCA;
{$APPTYPE CONSOLE}
uses
SysUtils, DateUtils,
WvdS.PqCrypto.FFI; // FFI unit s deklaracijama
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 Root-CA kreiranje ===');
WriteLn;
// 1. Inicijalizacija biblioteke
res := wvds_sec_crypto_x509_init();
if res <> WVDS_OK then
begin
WriteLn('GREŠKA: Inicijalizacija neuspješna (', res, ')');
Exit;
end;
try
// 2. Generiranje ML-DSA-65 para ključeva
WriteLn('Generiram ML-DSA-65 par ključeva...');
keypair := wvds_sec_crypto_x509_keypair_generate_mldsa(65);
if keypair = nil then
raise Exception.Create('Generiranje para ključeva neuspješno');
// Samotest
res := wvds_sec_crypto_x509_keypair_self_test(keypair);
if res <> WVDS_OK then
raise Exception.Create('Samotest para ključeva neuspješan');
WriteLn(' Samotest: OK');
// 3. Kreiranje Distinguished Name
WriteLn('Kreiram Distinguished Name...');
dn := wvds_sec_crypto_x509_dn_create();
if dn = nil then
raise Exception.Create('Kreiranje DN-a neuspješno');
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. Generiranje serijskog broja (20 bajtova = 160 bita)
WriteLn('Generiram serijski broj...');
res := wvds_sec_crypto_x509_serial_generate(@serial[0], 20);
if res <> WVDS_OK then
raise Exception.Create('Generiranje serijskog broja neuspješno');
// 5. Valjanost: 20 godina
WriteLn('Postavljam razdoblje valjanosti (20 godina)...');
validity := wvds_sec_crypto_x509_validity_create(
DateTimeToUnix(Now, False), // not_before: sada
DateTimeToUnix(IncYear(Now, 20), False) // not_after: +20 godina
);
if validity = nil then
raise Exception.Create('Kreiranje valjanosti neuspješno');
// 6. Kreiranje ekstenzija
WriteLn('Postavljam ekstenzije...');
ext := wvds_sec_crypto_x509_ext_create();
if ext = nil then
raise Exception.Create('Kreiranje ekstenzija neuspješno');
// 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 neuspješno');
// 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 neuspješno');
// Subject Key Identifier
res := wvds_sec_crypto_x509_ext_set_ski_from_keypair(ext, keypair);
if res <> WVDS_OK then
raise Exception.Create('SKI neuspješno');
// 7. Kreiranje Root certifikata (samopotpisan)
WriteLn('Kreiram samopotpisani Root certifikat...');
cert := wvds_sec_crypto_x509_cert_create_root(
keypair, // Par ključeva
dn, // Subject (= Issuer kod Root)
@serial[0], 20, // Serijski broj
validity, // Valjanost
ext // Ekstenzije
);
if cert = nil then
raise Exception.Create('Kreiranje certifikata neuspješno');
// 8. Spremanje kao PEM
WriteLn;
WriteLn('Spremam datoteke...');
// Certifikat
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('Izvoz certifikata neuspješan');
with TFileStream.Create('root-ca.crt.pem', fmCreate) do
try
Write(pem_buf[0], pem_len);
finally
Free;
end;
WriteLn(' root-ca.crt.pem spremljen');
// Privatni ključ (šifrirano)
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('Izvoz ključa neuspješan');
with TFileStream.Create('root-ca.key.pem', fmCreate) do
try
Write(pem_buf[0], pem_len);
finally
Free;
end;
WriteLn(' root-ca.key.pem spremljen (šifrirano)');
WriteLn;
WriteLn('=== Root-CA uspješno kreiran! ===');
finally
// 9. Čišćenje
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 ====
^ Parametar ^ Tip ^ Opis ^ Valjane vrijednosti ^
| ''level'' | ''u8'' | ML-DSA sigurnosna razina | ''44'', ''65'', ''87'' |
^ Razina ^ NIST sigurnost ^ Javni ključ ^ Privatni ključ ^ Potpis ^
| 44 | Razina 2 (~128-bit) | 1.312 bajtova | 2.560 bajtova | 2.420 bajtova |
| 65 | Razina 3 (~192-bit) | 1.952 bajtova | 4.032 bajtova | 3.293 bajtova |
| 87 | Razina 5 (~256-bit) | 2.592 bajtova | 4.896 bajtova | 4.595 bajtova |
==== wvds_sec_crypto_x509_dn_add_component ====
^ Parametar ^ Tip ^ Opis ^ Primjer ^
| ''dn'' | ''*mut DnHandle'' | DN handle | – |
| ''oid'' | ''*const c_char'' | OID kao string | ''"2.5.4.3"'' |
| ''value'' | ''*const c_char'' | UTF-8 vrijednost | ''"WvdS Root CA"'' |
^ OID ^ Konstanta ^ Opis ^ Primjer vrijednosti ^
| 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 znaka) | ''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 ====
^ Parametar ^ Tip ^ Opis ^ Vrijednost za Root-CA ^
| ''ext'' | ''*mut ExtHandle'' | Extension handle | – |
| ''ca'' | ''bool'' | Je li CA certifikat | ''true'' |
| ''path_len'' | ''i32'' | Max. duljina putanje (-1 = neograničeno) | ''1'' ili ''2'' |
==== wvds_sec_crypto_x509_ext_set_key_usage ====
^ Flag ^ Bit ^ Vrijednost ^ Opis ^
| digitalSignature | 0 | 0x0080 | Digitalni potpisi |
| nonRepudiation | 1 | 0x0040 | Neporecivost |
| keyEncipherment | 2 | 0x0020 | Šifriranje ključeva |
| dataEncipherment | 3 | 0x0010 | Šifriranje podataka |
| keyAgreement | 4 | 0x0008 | Dogovor ključeva |
| **keyCertSign** | 5 | 0x0004 | **Potpisivanje certifikata** ✓ |
| **cRLSign** | 6 | 0x0002 | **Potpisivanje CRL-a** ✓ |
| encipherOnly | 7 | 0x0001 | Samo šifriranje |
**Za Root-CA:** ''flags = 0x0006'' (keyCertSign + cRLSign)
----
===== Povratne vrijednosti =====
^ Kod ^ Konstanta ^ Značenje ^
| 0 | ''WVDS_OK'' | Uspjeh |
| 1 | ''WVDS_ERROR_INVALID_PARAMETER'' | Nevaljani parametar (npr. level ≠ 44/65/87) |
| 2 | ''WVDS_ERROR_OUT_OF_MEMORY'' | Alokacija memorije neuspješna |
| 3 | ''WVDS_ERROR_NOT_INITIALIZED'' | ''init()'' nije pozvan |
| 200 | ''WVDS_ERROR_KEY_GENERATION_FAILED'' | Generiranje ključa neuspješno |
| 201 | ''WVDS_ERROR_SIGNATURE_FAILED'' | Potpisivanje neuspješno |
| 210 | ''WVDS_ERROR_KEYPAIR_SELF_TEST_FAILED'' | Samotest neuspješan |
→ //Potpuni popis:// [[hr:int:pqcrypt:referenz:error_codes_tabelle|Kodovi grešaka]]
----
===== Izlazne datoteke =====
==== root-ca.crt.pem ====
-----BEGIN CERTIFICATE-----
MIIHxjCCBiagAwIBAgIUP7J2kM9x... (Base64-kodirani DER)
...
-----END CERTIFICATE-----
^ Polje ^ Vrijednost ^
| Version | 3 (0x02) |
| Serial | 20 bajtova slučajnih |
| 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 godina |
| Public Key | ML-DSA-65 (~1.952 bajtova) |
| Extensions | BasicConstraints, KeyUsage, SKI |
| Signature | ML-DSA-65 (~3.293 bajtova) |
==== root-ca.key.pem ====
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIHbTBXBgkqhkiG9w0BBQ0w... (PKCS#8 EncryptedPrivateKeyInfo)
...
-----END ENCRYPTED PRIVATE KEY-----
^ Polje ^ Vrijednost ^
| Format | PKCS#8 EncryptedPrivateKeyInfo |
| KDF | Argon2id (64MB, 3 iteracije, 4 trake) |
| Cipher | AES-256-GCM |
| Key Size | ~4.032 bajtova (ML-DSA-65 privatni ključ) |
----
===== Sigurnosne napomene =====
**KRITIČNO – Root-CA privatni ključ:**
Privatni ključ Root-CA je **najkritičniji sigurnosni element** cijele PKI. Kompromitacija znači potpuni gubitak povjerenja!
* **Nikada** ne generirati ili pohranjivati na mrežno povezanim sustavima
* **Nikada** ne pohranjivati nešifrirano
* **Nikada** ne prenositi e-mailom ili nesigurnim kanalima
**Preporučene zaštitne mjere:**
* **Air-Gapped sustav:** Root-CA operacije na izoliranom računalu bez mreže
* **HSM:** Hardware Security Module za pohranu ključeva (npr. YubiHSM, Thales Luna)
* **Šifriranje:** Minimalno AES-256 s jakom lozinkom (≥20 znakova)
* **Fizička sigurnost:** Šifrirani USB stick u sefu ili bankovnom sefu
* **Backup:** Minimalno 2 kopije na odvojenim lokacijama
* **Key Ceremony:** Dokumentiran proces sa svjedocima za sve Root-CA operacije
* **Audit log:** Protokolirati sve pristupe
**Best Practices:**
* **ML-DSA-65** pruža dobar omjer sigurnosti i performansi za Root-CA
* **pathLength=1** ograničava hijerarhiju na Root → Intermediate → End-Entity
* **20 godina valjanosti** je uobičajeno za Root-CA (max. 25 godina preporučeno)
* **SKI postaviti** omogućuje kasniju AKI referencu u Intermediate certifikatima
* **Samotest** nakon generiranja osigurava ispravnu implementaciju
----
===== Česte greške =====
^ Problem ^ Uzrok ^ Rješenje ^
| ''KEY_GENERATION_FAILED'' | Nedovoljno entropije | Provjeriti OS izvor slučajnosti, /dev/urandom dostupan? |
| ''KEYPAIR_SELF_TEST_FAILED'' | Neispravna implementacija | Provjeriti verziju biblioteke, ponovno kompilirati |
| Certifikat nevažeći | DN prazan | Minimalno postaviti CN |
| Ključ nečitljiv | Pogrešna lozinka | Provjeriti lozinku, encoding (UTF-8) |
| Greška pathLength | Vrijednost < -1 | -1 za neograničeno, 0, 1, 2, ... za ograničenje |
| ''NOT_INITIALIZED'' | ''init()'' zaboravljen | Prvo pozvati ''wvds_sec_crypto_x509_init()'' |
| Curenje memorije | Handle-i nisu oslobođeni | Pozvati sve ''free_*()'' funkcije |
| PEM prevelik | Buffer premalen | Prethodno upitati veličinu (out_len = 0) |
----
===== Povezani scenariji =====
^ Odnos ^ Scenarij ^ Opis ^
| **Sljedeći korak** | [[.:intermediate_ca_erstellen|1.2 Intermediate-CA]] | Potpisivanje podređenog CA od Root-a |
| **Zatim** | [[.:trust_store_konfigurieren|1.4 Trust Store]] | Distribucija Root certifikata |
| **Zatim** | [[.:crl_ocsp_infrastruktur|1.6 CRL/OCSP]] | Postavljanje servisa za opoziv |
| **Alternativno** | [[hr:int:pqcrypt:szenarien:schluessel:schluesselpaar_generieren|11.1 Generiranje ključeva]] | Samo ključevi, bez certifikata |
| **Povezano** | [[hr:int:pqcrypt:szenarien:schluessel:schluessel_speichern|11.2 Pohrana ključeva]] | Dodatne opcije pohrane |
----
===== Reference =====
=== API dokumentacija ===
* [[hr:int:pqcrypt:api:module:init|Modul: init]]
* [[hr:int:pqcrypt:api:module:keypair|Modul: keypair]]
* [[hr:int:pqcrypt:api:module:dn|Modul: dn]]
* [[hr:int:pqcrypt:api:module:cert|Modul: cert]]
* [[hr:int:pqcrypt:api:module:ext|Modul: ext]]
* [[hr:int:pqcrypt:api:module:free|Modul: free]]
=== Koncepti ===
* [[hr:int:pqcrypt:konzepte:fips_204_ml_dsa|ML-DSA (FIPS 204)]]
* [[hr:int:pqcrypt:konzepte:pki_grundlagen|Osnove PKI]]
* [[hr:int:pqcrypt:konzepte:x509_erweiterungen|X.509 ekstenzije]]
=== Sigurnost ===
* [[hr:int:pqcrypt:sicherheit:schluessellaengen|Preporučene duljine ključeva]]
* [[hr:int:pqcrypt:sicherheit:secure_memory|Sigurno upravljanje memorijom]]
=== Referentne tablice ===
* [[hr:int:pqcrypt:referenz:oid_tabelle|OID tablica]]
* [[hr:int:pqcrypt:referenz:error_codes_tabelle|Kodovi grešaka]]
* [[hr:int:pqcrypt:referenz:schluesselgroessen|Veličine ključeva]]
* [[hr:int:pqcrypt:referenz:signaturgroessen|Veličine potpisa]]
=== Vanjski standardi ===
* [[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 u X.509]]
----
<< [[.:start|← PKI infrastruktura]] | [[hr:int:pqcrypt:szenarien:start|▲ Scenariji]] | [[.:intermediate_ca_erstellen|1.2 Intermediate-CA →]] >>
{{tag>scenarij pki root-ca ml-dsa-65 samopotpisan keypair certifikat fips-204}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//
~~NOTOC~~