Scenario 10.2: Configurare client TLS
Categoria: TLS/mTLS
Complessità: Media
Prerequisiti: Trust Store, certificato client opzionale
Tempo stimato: 15-20 minuti
Descrizione
Questo scenario descrive la configurazione di un client TLS per connessioni sicure a server con certificati Post-Quantum.
Compiti del client:
- Validare certificato server
- Configurare Trust Store
- Versione TLS e Cipher Suites
- Opzionale: presentare certificato client
Workflow
flowchart LR
TRUST[Caricare Trust Store] --> CONNECT[Stabilire connessione]
CONNECT --> VERIFY[Verificare cert server]
VERIFY --> CHAIN[Validare chain]
CHAIN --> REV[Verificare revoca]
REV --> OK{Tutto OK?}
OK -->|Si| DATA[Trasferire dati]
OK -->|No| ABORT[Interrompere]
style DATA fill:#e8f5e9
style ABORT fill:#ffebee
Esempio codice: HttpClient con Trust Store personalizzato
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using var ctx = PqCryptoContext.Initialize(); // Caricare Trust Store personalizzato var trustedCerts = new X509Certificate2Collection(); trustedCerts.Add(ctx.LoadCertificate("company-root-ca.crt.pem")); trustedCerts.Add(ctx.LoadCertificate("company-intermediate-ca.crt.pem")); // Configurare HttpClientHandler var handler = new HttpClientHandler { // Validazione personalizzata certificato server ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { // Verificare prima gli errori standard if (errors == SslPolicyErrors.None) { return true; } // Per UntrustedRoot: usare Trust Store personalizzato if (errors == SslPolicyErrors.RemoteCertificateChainErrors) { var customChain = new X509Chain(); customChain.ChainPolicy.CustomTrustStore.AddRange(trustedCerts); customChain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; customChain.ChainPolicy.RevocationMode = X509RevocationMode.Online; customChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; bool isValid = customChain.Build(cert); if (!isValid) { foreach (var status in customChain.ChainStatus) { Console.WriteLine($"Errore chain: {status.StatusInformation}"); } } return isValid; } Console.WriteLine($"Errore SSL: {errors}"); return false; }, // Versione TLS SslProtocols = SslProtocols.Tls13, // Verifica revoca CheckCertificateRevocationList = true }; using var httpClient = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(30) }; // Eseguire richiesta var response = await httpClient.GetAsync("https://api.example.com/data"); Console.WriteLine($"Stato: {response.StatusCode}");
Esempio codice: Client TLS con SocketsHttpHandler
// SocketsHttpHandler per maggiore controllo var socketsHandler = new SocketsHttpHandler { // Connection Pooling PooledConnectionLifetime = TimeSpan.FromMinutes(15), PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2), MaxConnectionsPerServer = 10, // Configurazione TLS SslOptions = new SslClientAuthenticationOptions { // Forzare TLS 1.3 EnabledSslProtocols = SslProtocols.Tls13, // Nome server per SNI TargetHost = "api.example.com", // Callback validazione certificato RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => { if (errors == SslPolicyErrors.None) return true; // Logging Console.WriteLine($"Certificato: {certificate?.Subject}"); Console.WriteLine($"Errori: {errors}"); return false; // Validazione rigorosa }, // Protocolli applicazione (ALPN) ApplicationProtocols = new List<SslApplicationProtocol> { SslApplicationProtocol.Http2, SslApplicationProtocol.Http11 } } }; using var client = new HttpClient(socketsHandler);
Certificate Pinning
public class CertificatePinningHandler : HttpClientHandler { private readonly HashSet<string> _pinnedCertificates; public CertificatePinningHandler(params string[] pinnedThumbprints) { _pinnedCertificates = new HashSet<string>( pinnedThumbprints, StringComparer.OrdinalIgnoreCase ); ServerCertificateCustomValidationCallback = ValidateServerCertificate; } private bool ValidateServerCertificate( HttpRequestMessage message, X509Certificate2? cert, X509Chain? chain, SslPolicyErrors errors) { if (cert == null) return false; // 1. Validazione standard if (errors != SslPolicyErrors.None) { Console.WriteLine($"Errore SSL Policy: {errors}"); return false; } // 2. Verificare pin (Leaf o Intermediate) bool pinValid = false; // Verificare certificato leaf if (_pinnedCertificates.Contains(cert.Thumbprint)) { pinValid = true; } // Cercare nella chain if (!pinValid && chain != null) { foreach (var element in chain.ChainElements) { if (_pinnedCertificates.Contains(element.Certificate.Thumbprint)) { pinValid = true; break; } } } if (!pinValid) { Console.WriteLine($"Pin certificato non corrispondente: {cert.Thumbprint}"); } return pinValid; } } // Utilizzo var pinnedHandler = new CertificatePinningHandler( "A1B2C3D4E5F6...", // Thumbprint Leaf "B2C3D4E5F6G7..." // Thumbprint Intermediate (pin di backup) ); using var client = new HttpClient(pinnedHandler);
Gestione Trust Store
public class TrustStoreManager { private readonly X509Certificate2Collection _trustedRoots = new(); private readonly X509Certificate2Collection _trustedIntermediates = new(); public void AddTrustedRoot(string certPath) { var cert = new X509Certificate2(certPath); // Verificare se è un certificato CA var basicConstraints = cert.Extensions["2.5.29.19"] as X509BasicConstraintsExtension; if (basicConstraints == null || !basicConstraints.CertificateAuthority) { throw new ArgumentException("Non è un certificato CA"); } _trustedRoots.Add(cert); Console.WriteLine($"Trusted Root aggiunto: {cert.Subject}"); } public void AddTrustedIntermediate(string certPath) { var cert = new X509Certificate2(certPath); _trustedIntermediates.Add(cert); Console.WriteLine($"Trusted Intermediate aggiunto: {cert.Subject}"); } public X509Chain CreateChain() { var chain = new X509Chain(); chain.ChainPolicy.CustomTrustStore.AddRange(_trustedRoots); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; chain.ChainPolicy.ExtraStore.AddRange(_trustedIntermediates); chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15); return chain; } public bool ValidateCertificate(X509Certificate2 cert) { using var chain = CreateChain(); return chain.Build(cert); } }
Logica di retry per errori TLS
public class ResilientTlsClient { private readonly HttpClient _client; private readonly int _maxRetries; public ResilientTlsClient(HttpClient client, int maxRetries = 3) { _client = client; _maxRetries = maxRetries; } public async Task<HttpResponseMessage> GetWithRetry(string url) { Exception? lastException = null; for (int attempt = 1; attempt <= _maxRetries; attempt++) { try { return await _client.GetAsync(url); } catch (HttpRequestException ex) when (IsTlsError(ex)) { lastException = ex; Console.WriteLine($"Errore TLS (tentativo {attempt}/{_maxRetries}): {ex.Message}"); if (attempt < _maxRetries) { await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt))); } } } throw new HttpRequestException($"Fallito dopo {_maxRetries} tentativi", lastException); } private bool IsTlsError(HttpRequestException ex) { return ex.InnerException is AuthenticationException || ex.Message.Contains("SSL") || ex.Message.Contains("TLS"); } }
Requisiti client specifici per settore
| Settore | Trust Store | Pinning | Timeout |
|---|---|---|---|
| Finanza | PKI propria | Obbligatorio | 30s |
| Sanità | gematik TSL | Raccomandato | 60s |
| IoT | Integrato | Obbligatorio | 120s |
| Enterprise | Distribuito AD/GPO | Opzionale | 30s |
Scenari correlati
| Relazione | Scenario | Descrizione |
|---|---|---|
| Prerequisito | 10.1 Server TLS | Configurare server |
| Estensione | 10.3 Deployment mTLS | Aggiungere cert client |
| Correlato | 5.2 Validazione Chain | Verifica certificati |
« ← 10.1 Server TLS | ↑ Panoramica TLS | 10.3 Deployment mTLS → »
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional
Zuletzt geändert: il 30/01/2026 alle 07:00