Improper SSL/TLS Certificate Validation

Critical Risk Cryptographic Security
ssl-tlscertificate-validationhostname-verificationcertificate-pinningman-in-the-middlecertificate-chaintrust-validationhttps

What it is

A critical vulnerability where applications bypass or improperly implement SSL/TLS certificate validation, allowing man-in-the-middle attacks. This includes accepting self-signed certificates, ignoring hostname mismatches, disabling certificate verification, or failing to validate certificate chains properly.

// Swift iOS - VULNERABLE: Improper certificate validation in mobile app import Foundation import Network import Security class VulnerableNetworkManager { private let session: URLSession init() { // DANGEROUS: Custom session configuration that ignores SSL errors let config = URLSessionConfiguration.default self.session = URLSession( configuration: config, delegate: self, delegateQueue: nil ) } func makeRequest(to url: URL, completion: @escaping (Data?, Error?) -> Void) { let task = session.dataTask(with: url) { data, response, error in completion(data, error) } task.resume() } func downloadFile(from url: URL, completion: @escaping (Data?, Error?) -> Void) { makeRequest(to: url, completion: completion) } } // VULNERABLE: URLSessionDelegate that accepts all certificates extension VulnerableNetworkManager: URLSessionDelegate { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { // DANGEROUS: Always accept any certificate without validation! let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!) completionHandler(.useCredential, credential) } } // VULNERABLE: Even worse - manual certificate bypass class UnsafeNetworkManager { func makeUnsafeRequest(to urlString: String, completion: @escaping (String?) -> Void) { guard let url = URL(string: urlString) else { completion(nil) return } var request = URLRequest(url: url) // DANGEROUS: Adding headers to bypass security request.setValue("*", forHTTPHeaderField: "Accept") request.setValue("no-check", forHTTPHeaderField: "SSL-Verify") let task = URLSession.shared.dataTask(with: request) { data, response, error in // Ignoring SSL errors if let error = error as NSError?, error.domain == NSURLErrorDomain { switch error.code { case NSURLErrorServerCertificateHasBadDate, NSURLErrorServerCertificateUntrusted, NSURLErrorServerCertificateHasUnknownRoot, NSURLErrorServerCertificateNotYetValid: // DANGEROUS: Ignoring certificate errors print("Ignoring SSL error: \(error.localizedDescription)") completion("SSL error ignored") return default: break } } if let data = data { completion(String(data: data, encoding: .utf8)) } else { completion(nil) } } task.resume() } // VULNERABLE: Manual certificate checking that always returns true func validateCertificate(_ trust: SecTrust) -> Bool { // NEVER do this - always returns true! return true } } // VULNERABLE: Network reachability without security checks class InsecureAPIClient { func loginUser(username: String, password: String, completion: @escaping (Bool) -> Void) { // DANGEROUS: Sending credentials over potentially insecure connection let urlString = "https://api.example.com/login" guard let url = URL(string: urlString) else { completion(false) return } var request = URLRequest(url: url) request.httpMethod = "POST" let credentials = ["username": username, "password": password] request.httpBody = try? JSONSerialization.data(withJSONObject: credentials) // Using default session without any certificate validation URLSession.shared.dataTask(with: request) { data, response, error in // Not checking if connection was actually secure completion(error == nil) }.resume() } }
// Swift iOS - SECURE: Proper certificate validation with pinning import Foundation import Network import Security import CryptoKit import CommonCrypto class SecureNetworkManager { private let session: URLSession private let pinnedCertificates: [String] // SHA-256 hashes private let trustedDomains: [String] init(pinnedCertHashes: [String] = [], trustedDomains: [String] = []) { self.pinnedCertificates = pinnedCertHashes self.trustedDomains = trustedDomains let config = URLSessionConfiguration.default config.timeoutIntervalForRequest = 30 config.timeoutIntervalForResource = 60 // Enable TLS 1.2+ only config.tlsMinimumSupportedProtocolVersion = .TLSv12 self.session = URLSession( configuration: config, delegate: self, delegateQueue: nil ) } func makeSecureRequest(to url: URL, completion: @escaping (Result) -> Void) { // Validate URL scheme guard url.scheme == "https" else { completion(.failure(.insecureScheme)) return } // Validate domain if restricted if !trustedDomains.isEmpty { guard let host = url.host, isDomainTrusted(host) else { completion(.failure(.untrustedDomain)) return } } let task = session.dataTask(with: url) { data, response, error in if let error = error { completion(.failure(.networkError(error))) return } // Validate HTTPS response guard let httpResponse = response as? HTTPURLResponse, let data = data else { completion(.failure(.invalidResponse)) return } // Check for secure connection if let url = httpResponse.url, url.scheme != "https" { completion(.failure(.insecureResponse)) return } completion(.success(data)) } task.resume() } private func isDomainTrusted(_ domain: String) -> Bool { return trustedDomains.contains { trusted in if trusted.hasPrefix("*.") { let wildcardDomain = String(trusted.dropFirst(2)) return domain.hasSuffix(wildcardDomain) } return domain == trusted } } } // SECURE: Comprehensive certificate validation extension SecureNetworkManager: URLSessionDelegate { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { // Only handle server trust challenges guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust else { completionHandler(.performDefaultHandling, nil) return } guard let serverTrust = challenge.protectionSpace.serverTrust else { completionHandler(.cancelAuthenticationChallenge, nil) return } // Perform comprehensive certificate validation let validationResult = validateServerTrust(serverTrust, for: challenge.protectionSpace.host) switch validationResult { case .success: let credential = URLCredential(trust: serverTrust) completionHandler(.useCredential, credential) case .failure(let error): print("Certificate validation failed: \(error.localizedDescription)") completionHandler(.cancelAuthenticationChallenge, nil) } } private func validateServerTrust(_ serverTrust: SecTrust, for hostname: String) -> Result { // Step 1: Set SSL policy for hostname verification let policy = SecPolicyCreateSSL(true, hostname as CFString) let status = SecTrustSetPolicies(serverTrust, policy) guard status == errSecSuccess else { return .failure(.policySetFailed) } // Step 2: Evaluate trust var trustResult: SecTrustResultType = .invalid let evaluationStatus = SecTrustEvaluate(serverTrust, &trustResult) guard evaluationStatus == errSecSuccess else { return .failure(.trustEvaluationFailed) } // Step 3: Check trust result guard trustResult == .unspecified || trustResult == .proceed else { return .failure(.trustValidationFailed(trustResult)) } // Step 4: Validate certificate details guard let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else { return .failure(.certificateNotFound) } // Step 5: Check certificate expiration if let expirationDate = getCertificateExpirationDate(serverCertificate) { let now = Date() if expirationDate < now { return .failure(.certificateExpired) } // Warn if certificate expires soon (30 days) if expirationDate.timeIntervalSince(now) < 30 * 24 * 60 * 60 { print("Warning: Certificate for \(hostname) expires soon: \(expirationDate)") } } // Step 6: Perform certificate pinning if configured if !pinnedCertificates.isEmpty { let pinningResult = validateCertificatePinning(serverTrust) if case .failure(let error) = pinningResult { return .failure(error) } } // Step 7: Additional certificate validation return validateCertificateExtended(serverCertificate, hostname: hostname) } private func validateCertificatePinning(_ serverTrust: SecTrust) -> Result { let certificateCount = SecTrustGetCertificateCount(serverTrust) for i in 0.. String? { guard let publicKey = SecCertificateCopyKey(certificate) else { return nil } guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, nil) else { return nil } let data = publicKeyData as Data let hash = SHA256.hash(data: data) return "sha256:" + Data(hash).base64EncodedString() } private func getCertificateExpirationDate(_ certificate: SecCertificate) -> Date? { guard let certificateData = SecCertificateCopyData(certificate) else { return nil } let data = certificateData as Data // Parse X.509 certificate (simplified - use proper ASN.1 parsing in production) // This is a basic implementation - consider using a proper certificate parsing library return nil // Placeholder - implement proper X.509 parsing } private func validateCertificateExtended(_ certificate: SecCertificate, hostname: String) -> Result { // Validate certificate subject guard let subject = getCertificateSubject(certificate) else { return .failure(.invalidCertificateSubject) } // Check for critical extensions if !hasCriticalExtensions(certificate) { return .failure(.missingCriticalExtensions) } return .success(()) } private func getCertificateSubject(_ certificate: SecCertificate) -> String? { var commonName: CFString? let status = SecCertificateCopyCommonName(certificate, &commonName) guard status == errSecSuccess, let cn = commonName else { return nil } return cn as String } private func hasCriticalExtensions(_ certificate: SecCertificate) -> Bool { // Check for required extensions like Subject Alternative Name, Key Usage, etc. // This is a simplified check - implement proper extension validation return true // Placeholder } } // SECURE: API client with proper certificate validation class SecureAPIClient { private let networkManager: SecureNetworkManager init() { // Configure with certificate pinning and trusted domains self.networkManager = SecureNetworkManager( pinnedCertHashes: [ "sha256:YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=", // Example pin "sha256:Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=" // Backup pin ], trustedDomains: [ "api.example.com", "*.example.com" ] ) } func loginUser(username: String, password: String, completion: @escaping (Result) -> Void) { guard let url = URL(string: "https://api.example.com/login") else { completion(.failure(.invalidURL)) return } var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") let credentials = LoginRequest(username: username, password: password) do { request.httpBody = try JSONEncoder().encode(credentials) } catch { completion(.failure(.encodingError)) return } networkManager.makeSecureRequest(to: url) { result in switch result { case .success(let data): do { let authResponse = try JSONDecoder().decode(AuthResponse.self, from: data) completion(.success(authResponse)) } catch { completion(.failure(.decodingError)) } case .failure(let error): completion(.failure(error)) } } } } // Supporting types struct LoginRequest: Codable { let username: String let password: String } struct AuthResponse: Codable { let token: String let expiresIn: Int } enum NetworkError: Error { case insecureScheme case untrustedDomain case networkError(Error) case invalidResponse case insecureResponse case invalidURL case encodingError case decodingError } enum CertificateError: Error { case policySetFailed case trustEvaluationFailed case trustValidationFailed(SecTrustResultType) case certificateNotFound case certificateExpired case certificatePinningFailed case invalidCertificateSubject case missingCriticalExtensions }

💡 Why This Fix Works

The vulnerable implementation completely bypasses SSL certificate validation, ignores all certificate errors, and sends credentials over potentially insecure connections. The secure version implements comprehensive certificate validation including trust evaluation, hostname verification, certificate pinning, expiration checking, and proper error handling.

Why it happens

Developers disable SSL certificate verification in HTTP clients to bypass certificate errors during development or when dealing with self-signed certificates. This dangerous practice often makes it to production, leaving applications vulnerable to man-in-the-middle attacks.

Root causes

Disabled Certificate Verification in HTTP Clients

Developers disable SSL certificate verification in HTTP clients to bypass certificate errors during development or when dealing with self-signed certificates. This dangerous practice often makes it to production, leaving applications vulnerable to man-in-the-middle attacks.

Preview example – PYTHON
// Python - VULNERABLE: Disabled certificate verification
import requests
import urllib3
from requests.packages.urllib3.exceptions import InsecureRequestWarning

# DANGEROUS: Disabling SSL warnings and verification
urllib3.disable_warnings(InsecureRequestWarning)
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

class VulnerableHttpClient:
    def __init__(self):
        self.session = requests.Session()
        # NEVER do this in production!
        self.session.verify = False  # Disables all SSL verification
    
    def make_api_call(self, url, data):
        # Vulnerable API call without certificate validation
        response = self.session.post(
            url, 
            json=data, 
            verify=False,  # Disables SSL verification
            timeout=30
        )
        return response.json()
    
    def download_file(self, url):
        # Downloading files without certificate validation
        response = requests.get(url, verify=False, stream=True)
        return response.content

Custom Trust Managers That Accept All Certificates

Implementing custom trust managers or certificate validators that accept all certificates without proper validation. This is often done to handle self-signed certificates but completely breaks the security model of TLS.

Preview example – JAVA
// Java - VULNERABLE: Custom trust manager accepting all certificates
import javax.net.ssl.*;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.net.HttpURLConnection;
import java.net.URL;

public class VulnerableTrustManager {
    
    // DANGEROUS: Trust manager that accepts all certificates
    private static class AcceptAllTrustManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) 
                throws CertificateException {
            // NEVER do this - accepts any client certificate!
        }
        
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) 
                throws CertificateException {
            // NEVER do this - accepts any server certificate!
        }
        
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }
    
    // DANGEROUS: Hostname verifier that accepts all hostnames
    private static class AcceptAllHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true; // NEVER do this - accepts any hostname!
        }
    }
    
    public static void disableSSLVerification() {
        try {
            // Create trust manager that accepts all certificates
            TrustManager[] trustAllCerts = new TrustManager[] {
                new AcceptAllTrustManager()
            };
            
            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            
            // Set default SSL context
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new AcceptAllHostnameVerifier());
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public String makeVulnerableRequest(String urlString) throws Exception {
        // Disable SSL verification globally
        disableSSLVerification();
        
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        
        // Connection is now vulnerable to MITM attacks
        return connection.getResponseMessage();
    }
}

Ignoring Certificate Hostname Mismatches

Applications that check certificate validity but ignore hostname verification, allowing attackers to use valid certificates for different domains. This is common when using certificates with different Subject Alternative Names or when connecting to services by IP address.

Preview example – JAVASCRIPT
// Node.js - VULNERABLE: Ignoring hostname verification
const https = require('https');
const tls = require('tls');

class VulnerableHttpsClient {
    constructor() {
        // DANGEROUS: Disable hostname checking globally
        process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
    }
    
    makeRequest(hostname, path) {
        const options = {
            hostname: hostname,
            port: 443,
            path: path,
            method: 'GET',
            // VULNERABLE: Ignoring certificate errors
            rejectUnauthorized: false,  // Accepts invalid certificates
            checkServerIdentity: () => {  // Bypasses hostname verification
                return undefined; // NEVER return undefined here!
            }
        };
        
        return new Promise((resolve, reject) => {
            const req = https.request(options, (res) => {
                let data = '';
                res.on('data', chunk => data += chunk);
                res.on('end', () => resolve(data));
            });
            
            // DANGEROUS: Ignoring certificate errors
            req.on('error', (err) => {
                console.log('Ignoring SSL error:', err.message);
                resolve(''); // Should reject, not resolve!
            });
            
            req.end();
        });
    }
    
    connectWithCustomTLS(hostname, port) {
        // VULNERABLE: Custom TLS connection without proper validation
        const socket = tls.connect(port, hostname, {
            rejectUnauthorized: false,  // Dangerous!
            checkServerIdentity: () => undefined  // Bypasses hostname check
        });
        
        return socket;
    }
}

Missing Certificate Chain Validation

Failing to validate the complete certificate chain, intermediate certificates, or certificate revocation status. This can allow attackers to use compromised intermediate certificates or certificates that have been revoked but are still technically valid.

Preview example – CSHARP
// C# - VULNERABLE: Inadequate certificate validation
using System;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Net.Http;

public class VulnerableCertificateValidation
{
    public VulnerableCertificateValidation()
    {
        // DANGEROUS: Accept all certificates globally
        ServicePointManager.ServerCertificateValidationCallback = 
            (sender, certificate, chain, sslPolicyErrors) => true; // NEVER do this!
        
        // DANGEROUS: Allow weak TLS protocols
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | 
                                               SecurityProtocolType.Tls |
                                               SecurityProtocolType.Tls11;
    }
    
    // VULNERABLE: Custom validation that ignores critical errors
    private static bool WeakCertificateValidation(
        object sender,
        X509Certificate certificate,
        X509Chain chain,
        SslPolicyErrors sslPolicyErrors)
    {
        // DANGEROUS: Only checking if certificate exists
        if (certificate == null)
            return false;
        
        // VULNERABLE: Ignoring all SSL policy errors
        // This ignores hostname mismatches, untrusted CAs, expired certificates, etc.
        return true;
    }
    
    public async Task<string> MakeVulnerableHttpRequest(string url)
    {
        using (var handler = new HttpClientHandler())
        {
            // DANGEROUS: Disable certificate validation
            handler.ServerCertificateCustomValidationCallback = 
                (message, cert, chain, errors) => true;
            
            using (var client = new HttpClient(handler))
            {
                var response = await client.GetStringAsync(url);
                return response;
            }
        }
    }
    
    // VULNERABLE: Manual certificate validation with flaws
    private static bool FlawedCertificateValidation(
        object sender,
        X509Certificate certificate,
        X509Chain chain,
        SslPolicyErrors sslPolicyErrors)
    {
        // Only checking for no errors, but not validating chain properly
        if (sslPolicyErrors == SslPolicyErrors.None)
            return true;
        
        // VULNERABLE: Accepting hostname mismatches
        if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateNameMismatch)
            return true; // DANGEROUS!
        
        // VULNERABLE: Accepting chain errors without investigation
        if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors)
        {
            // Should check chain.ChainStatus for specific errors
            return true; // DANGEROUS!
        }
        
        return false;
    }
}

Fixes

1

Implement Proper Certificate Validation

Always validate SSL/TLS certificates properly by checking the certificate chain, hostname verification, expiration dates, and trusted certificate authorities. Never disable certificate validation in production code and use proper error handling for certificate failures.

View implementation – PYTHON
# Python - SECURE: Proper certificate validation
import requests
import ssl
from urllib.parse import urlparse
from cryptography import x509
from cryptography.hazmat.backends import default_backend
import socket
import datetime

class SecureHttpClient:
    def __init__(self, ca_bundle_path=None):
        self.session = requests.Session()
        
        # Use system CA bundle or custom one
        if ca_bundle_path:
            self.session.verify = ca_bundle_path
        else:
            self.session.verify = True  # Use system CA bundle
        
        # Set secure defaults
        self.session.headers.update({
            'User-Agent': 'SecureClient/1.0'
        })
        
        # Configure SSL context with secure settings
        self.ssl_context = ssl.create_default_context()
        self.ssl_context.check_hostname = True
        self.ssl_context.verify_mode = ssl.CERT_REQUIRED
        
        # Disable weak protocols
        self.ssl_context.options |= ssl.OP_NO_SSLv2
        self.ssl_context.options |= ssl.OP_NO_SSLv3
        self.ssl_context.options |= ssl.OP_NO_TLSv1
        self.ssl_context.options |= ssl.OP_NO_TLSv1_1
    
    def validate_certificate_manually(self, hostname, port=443):
        """Manually validate certificate for additional checks"""
        try:
            # Get certificate
            cert_der = ssl.get_server_certificate((hostname, port))
            cert = x509.load_pem_x509_certificate(cert_der.encode(), default_backend())
            
            # Check expiration
            now = datetime.datetime.now()
            if cert.not_valid_after < now:
                raise ValueError(f"Certificate expired on {cert.not_valid_after}")
            
            if cert.not_valid_before > now:
                raise ValueError(f"Certificate not yet valid until {cert.not_valid_before}")
            
            # Check hostname in SAN
            try:
                san_extension = cert.extensions.get_extension_for_oid(
                    x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME
                )
                san_names = san_extension.value.get_values_for_type(x509.DNSName)
                
                if hostname not in san_names:
                    # Check if it matches any wildcard
                    hostname_match = False
                    for san_name in san_names:
                        if san_name.startswith('*.') and hostname.endswith(san_name[2:]):
                            hostname_match = True
                            break
                    
                    if not hostname_match:
                        raise ValueError(f"Hostname {hostname} not in certificate SAN")
                        
            except x509.ExtensionNotFound:
                # Check CN in subject if no SAN
                subject_cn = None
                for attribute in cert.subject:
                    if attribute.oid == x509.NameOID.COMMON_NAME:
                        subject_cn = attribute.value
                        break
                
                if subject_cn != hostname:
                    raise ValueError(f"Hostname {hostname} doesn't match certificate CN {subject_cn}")
            
            return True
            
        except Exception as e:
            print(f"Certificate validation failed: {e}")
            return False
    
    def make_secure_request(self, url, **kwargs):
        """Make HTTP request with proper certificate validation"""
        try:
            # Parse hostname for additional validation
            parsed_url = urlparse(url)
            if parsed_url.scheme == 'https':
                # Perform additional certificate validation
                if not self.validate_certificate_manually(parsed_url.hostname):
                    raise requests.exceptions.SSLError("Additional certificate validation failed")
            
            # Make request with full validation enabled
            response = self.session.get(url, **kwargs)
            response.raise_for_status()
            
            return response
            
        except requests.exceptions.SSLError as e:
            print(f"SSL Error: {e}")
            raise
        except requests.exceptions.RequestException as e:
            print(f"Request Error: {e}")
            raise
    
    def download_file_securely(self, url, output_path):
        """Download file with certificate validation"""
        try:
            with self.session.get(url, stream=True) as response:
                response.raise_for_status()
                
                with open(output_path, 'wb') as f:
                    for chunk in response.iter_content(chunk_size=8192):
                        f.write(chunk)
                        
            return True
            
        except Exception as e:
            print(f"Secure download failed: {e}")
            return False
2

Implement Certificate Pinning

Use certificate pinning to bind your application to specific certificates or certificate authorities. This provides protection against compromised CAs and man-in-the-middle attacks even with valid certificates from untrusted sources.

View implementation – JAVA
// Java - SECURE: Certificate pinning implementation
import javax.net.ssl.*;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.io.IOException;
import okhttp3.CertificatePinner;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class SecureCertificateValidation {
    
    // SHA-256 hashes of pinned certificates (public key hashes)
    private static final Set<String> PINNED_CERTIFICATES = new HashSet<>(Arrays.asList(
        "sha256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Example pin
        "sha256:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB="  // Backup pin
    ));
    
    private static final String[] TRUSTED_HOSTNAMES = {
        "api.example.com",
        "secure.example.com"
    };
    
    public static class SecureTrustManager implements X509TrustManager {
        private final X509TrustManager defaultTrustManager;
        
        public SecureTrustManager() throws Exception {
            TrustManagerFactory factory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm()
            );
            factory.init((KeyStore) null);
            
            for (TrustManager tm : factory.getTrustManagers()) {
                if (tm instanceof X509TrustManager) {
                    this.defaultTrustManager = (X509TrustManager) tm;
                    return;
                }
            }
            
            throw new Exception("No X509TrustManager found");
        }
        
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) 
                throws CertificateException {
            defaultTrustManager.checkClientTrusted(chain, authType);
        }
        
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) 
                throws CertificateException {
            // First, perform standard validation
            defaultTrustManager.checkServerTrusted(chain, authType);
            
            // Then, perform certificate pinning
            validateCertificatePinning(chain);
        }
        
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return defaultTrustManager.getAcceptedIssuers();
        }
        
        private void validateCertificatePinning(X509Certificate[] chain) 
                throws CertificateException {
            try {
                boolean pinMatched = false;
                
                // Check each certificate in the chain
                for (X509Certificate cert : chain) {
                    // Get public key and calculate SHA-256 hash
                    byte[] publicKeyBytes = cert.getPublicKey().getEncoded();
                    MessageDigest digest = MessageDigest.getInstance("SHA-256");
                    byte[] hash = digest.digest(publicKeyBytes);
                    
                    // Convert to base64
                    String hashString = "sha256:" + 
                        java.util.Base64.getEncoder().encodeToString(hash);
                    
                    if (PINNED_CERTIFICATES.contains(hashString)) {
                        pinMatched = true;
                        break;
                    }
                }
                
                if (!pinMatched) {
                    throw new CertificateException("Certificate pinning failed - no matching pins found");
                }
                
            } catch (Exception e) {
                throw new CertificateException("Certificate pinning validation failed", e);
            }
        }
    }
    
    public static class SecureHostnameVerifier implements HostnameVerifier {
        private final HostnameVerifier defaultVerifier;
        
        public SecureHostnameVerifier() {
            this.defaultVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
        }
        
        @Override
        public boolean verify(String hostname, SSLSession session) {
            // First, perform default hostname verification
            if (!defaultVerifier.verify(hostname, session)) {
                return false;
            }
            
            // Additional hostname validation
            return validateHostname(hostname);
        }
        
        private boolean validateHostname(String hostname) {
            // Check if hostname is in our trusted list
            for (String trustedHostname : TRUSTED_HOSTNAMES) {
                if (hostname.equals(trustedHostname) || 
                    (trustedHostname.startsWith("*.") && 
                     hostname.endsWith(trustedHostname.substring(2)))) {
                    return true;
                }
            }
            
            return false;
        }
    }
    
    public static OkHttpClient createSecureHttpClient() {
        try {
            // Create custom trust manager with pinning
            TrustManager[] trustManagers = { new SecureTrustManager() };
            
            // Create SSL context
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagers, new java.security.SecureRandom());
            
            // Build certificate pinner
            CertificatePinner certificatePinner = new CertificatePinner.Builder()
                .add("api.example.com", "sha256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
                .add("api.example.com", "sha256:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=")
                .build();
            
            // Create secure OkHttp client
            return new OkHttpClient.Builder()
                .sslSocketFactory(sslContext.getSocketFactory(), 
                                (X509TrustManager) trustManagers[0])
                .hostnameVerifier(new SecureHostnameVerifier())
                .certificatePinner(certificatePinner)
                .build();
                
        } catch (Exception e) {
            throw new RuntimeException("Failed to create secure HTTP client", e);
        }
    }
    
    public static String makeSecureRequest(String url) throws IOException {
        OkHttpClient client = createSecureHttpClient();
        
        Request request = new Request.Builder()
            .url(url)
            .build();
        
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("Unexpected response: " + response);
            }
            
            return response.body().string();
        }
    }
}
3

Configure Secure TLS Settings

Configure applications to use only secure TLS versions and cipher suites. Disable weak protocols, implement proper error handling for certificate validation failures, and use modern TLS configurations.

View implementation – JAVASCRIPT
// Node.js - SECURE: Proper TLS configuration and validation
const https = require('https');
const tls = require('tls');
const crypto = require('crypto');
const fs = require('fs');

class SecureHttpsClient {
    constructor(options = {}) {
        this.pinnedCertificates = options.pinnedCertificates || [];
        this.trustedHosts = options.trustedHosts || [];
        
        // Configure secure TLS options
        this.secureOptions = {
            // Require TLS 1.2 or higher
            secureProtocol: 'TLSv1_2_method',
            
            // Enable certificate verification
            rejectUnauthorized: true,
            
            // Custom server identity check
            checkServerIdentity: this.checkServerIdentity.bind(this),
            
            // Secure cipher suites only
            ciphers: [
                'ECDHE-RSA-AES256-GCM-SHA384',
                'ECDHE-RSA-AES128-GCM-SHA256',
                'ECDHE-RSA-AES256-SHA384',
                'ECDHE-RSA-AES128-SHA256'
            ].join(':'),
            
            // Honor server cipher order
            honorCipherOrder: true,
            
            // Minimum TLS version
            minVersion: 'TLSv1.2'
        };
    }
    
    checkServerIdentity(hostname, cert) {
        // First, perform default hostname verification
        const err = tls.checkServerIdentity(hostname, cert);
        if (err) {
            return err;
        }
        
        // Additional hostname validation
        if (this.trustedHosts.length > 0 && !this.isHostnameTrusted(hostname)) {
            return new Error(`Hostname ${hostname} is not in trusted hosts list`);
        }
        
        // Certificate pinning validation
        if (this.pinnedCertificates.length > 0) {
            return this.validateCertificatePinning(cert);
        }
        
        // Additional certificate validation
        return this.validateCertificateExtended(cert, hostname);
    }
    
    isHostnameTrusted(hostname) {
        return this.trustedHosts.some(trusted => {
            if (trusted.startsWith('*.')) {
                const domain = trusted.slice(2);
                return hostname.endsWith(domain);
            }
            return hostname === trusted;
        });
    }
    
    validateCertificatePinning(cert) {
        try {
            // Calculate certificate fingerprint
            const publicKey = cert.pubkey;
            const hash = crypto.createHash('sha256').update(publicKey).digest('base64');
            const pin = `sha256:${hash}`;
            
            if (!this.pinnedCertificates.includes(pin)) {
                return new Error(`Certificate pinning failed. Expected pins: ${this.pinnedCertificates.join(', ')}`);
            }
            
            return undefined; // Valid
            
        } catch (error) {
            return new Error(`Certificate pinning validation error: ${error.message}`);
        }
    }
    
    validateCertificateExtended(cert, hostname) {
        try {
            // Check certificate validity period
            const now = new Date();
            const validFrom = new Date(cert.valid_from);
            const validTo = new Date(cert.valid_to);
            
            if (now < validFrom) {
                return new Error(`Certificate not yet valid. Valid from: ${validFrom}`);
            }
            
            if (now > validTo) {
                return new Error(`Certificate expired. Valid until: ${validTo}`);
            }
            
            // Check for critical extensions
            if (cert.ext_key_usage && !cert.ext_key_usage.includes('1.3.6.1.5.5.7.3.1')) {
                return new Error('Certificate missing serverAuth extended key usage');
            }
            
            // Validate certificate chain length
            if (cert.issuerCertificate && this.getCertificateChainDepth(cert) > 5) {
                return new Error('Certificate chain too long');
            }
            
            return undefined; // Valid
            
        } catch (error) {
            return new Error(`Extended certificate validation error: ${error.message}`);
        }
    }
    
    getCertificateChainDepth(cert, depth = 0) {
        if (!cert.issuerCertificate || cert.fingerprint === cert.issuerCertificate.fingerprint) {
            return depth;
        }
        return this.getCertificateChainDepth(cert.issuerCertificate, depth + 1);
    }
    
    makeSecureRequest(url, options = {}) {
        return new Promise((resolve, reject) => {
            const urlObj = new URL(url);
            
            const requestOptions = {
                hostname: urlObj.hostname,
                port: urlObj.port || 443,
                path: urlObj.pathname + urlObj.search,
                method: options.method || 'GET',
                headers: options.headers || {},
                ...this.secureOptions
            };
            
            const req = https.request(requestOptions, (res) => {
                let data = '';
                
                res.on('data', chunk => {
                    data += chunk;
                });
                
                res.on('end', () => {
                    resolve({
                        statusCode: res.statusCode,
                        headers: res.headers,
                        data: data,
                        certificate: res.socket.getPeerCertificate()
                    });
                });
            });
            
            req.on('error', (err) => {
                reject(new Error(`HTTPS request failed: ${err.message}`));
            });
            
            // Handle TLS errors specifically
            req.on('socket', (socket) => {
                socket.on('secureConnect', () => {
                    const cert = socket.getPeerCertificate(true);
                    console.log(`Secure connection established to ${urlObj.hostname}`);
                    console.log(`Certificate subject: ${cert.subject.CN}`);
                    console.log(`Certificate valid until: ${cert.valid_to}`);
                });
                
                socket.on('error', (err) => {
                    if (err.code === 'CERT_HAS_EXPIRED') {
                        reject(new Error('Certificate has expired'));
                    } else if (err.code === 'DEPTH_ZERO_SELF_SIGNED_CERT') {
                        reject(new Error('Self-signed certificate'));
                    } else {
                        reject(err);
                    }
                });
            });
            
            if (options.data) {
                req.write(options.data);
            }
            
            req.end();
        });
    }
    
    async testConnection(hostname, port = 443) {
        try {
            const response = await this.makeSecureRequest(`https://${hostname}:${port}/`);
            return {
                success: true,
                certificate: response.certificate,
                message: 'Connection successful'
            };
        } catch (error) {
            return {
                success: false,
                error: error.message,
                message: 'Connection failed'
            };
        }
    }
}
4

Implement Certificate Monitoring and Validation

Set up comprehensive certificate monitoring, validation, and alerting systems. Regularly check certificate expiration dates, validate certificate chains, and implement automated certificate renewal processes.

View implementation – CSHARP
// C# - SECURE: Comprehensive certificate validation and monitoring
using System;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Text;

public class SecureCertificateValidator
{
    private readonly HashSet<string> pinnedCertificateHashes;
    private readonly HashSet<string> trustedHostnames;
    private readonly TimeSpan certificateExpirationWarningPeriod;
    
    public SecureCertificateValidator(
        IEnumerable<string> pinnedHashes = null,
        IEnumerable<string> trustedHosts = null,
        TimeSpan? warningPeriod = null)
    {
        pinnedCertificateHashes = new HashSet<string>(pinnedHashes ?? Enumerable.Empty<string>());
        trustedHostnames = new HashSet<string>(trustedHosts ?? Enumerable.Empty<string>());
        certificateExpirationWarningPeriod = warningPeriod ?? TimeSpan.FromDays(30);
    }
    
    public bool ValidateCertificate(
        object sender,
        X509Certificate certificate,
        X509Chain chain,
        SslPolicyErrors sslPolicyErrors)
    {
        var request = sender as HttpWebRequest;
        var hostname = request?.Host ?? "unknown";
        
        try {
            // Step 1: Check for any SSL policy errors
            if (sslPolicyErrors != SslPolicyErrors.None)
            {
                LogCertificateError($"SSL Policy Errors for {hostname}: {sslPolicyErrors}");
                
                // Only proceed if we can handle specific errors
                if (!CanHandlePolicyErrors(sslPolicyErrors, hostname))
                {
                    return false;
                }
            }
            
            // Step 2: Convert to X509Certificate2 for detailed validation
            var cert2 = new X509Certificate2(certificate);
            
            // Step 3: Validate certificate chain
            if (!ValidateCertificateChain(chain, hostname))
            {
                return false;
            }
            
            // Step 4: Validate certificate details
            if (!ValidateCertificateDetails(cert2, hostname))
            {
                return false;
            }
            
            // Step 5: Perform certificate pinning if configured
            if (pinnedCertificateHashes.Any() && !ValidateCertificatePinning(cert2, chain))
            {
                return false;
            }
            
            // Step 6: Check trusted hostnames if configured
            if (trustedHostnames.Any() && !IsHostnameTrusted(hostname))
            {
                LogCertificateError($"Hostname {hostname} is not in trusted hosts list");
                return false;
            }
            
            // Step 7: Log certificate information for monitoring
            LogCertificateInfo(cert2, hostname);
            
            return true;
        }
        catch (Exception ex)
        {
            LogCertificateError($"Certificate validation exception for {hostname}: {ex.Message}");
            return false;
        }
    }
    
    private bool CanHandlePolicyErrors(SslPolicyErrors sslPolicyErrors, string hostname)
    {
        // Never allow these critical errors
        if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable))
        {
            return false;
        }
        
        // Hostname mismatch might be acceptable for trusted hosts with proper validation
        if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch))
        {
            // Only allow if hostname is explicitly trusted and we have certificate pinning
            return IsHostnameTrusted(hostname) && pinnedCertificateHashes.Any();
        }
        
        return false;
    }
    
    private bool ValidateCertificateChain(X509Chain chain, string hostname)
    {
        if (chain == null)
        {
            LogCertificateError($"Certificate chain is null for {hostname}");
            return false;
        }
        
        // Check chain status
        foreach (var status in chain.ChainStatus)
        {
            // Allow certain non-critical errors
            if (IsChainStatusCritical(status.Status))
            {
                LogCertificateError($"Critical chain status error for {hostname}: {status.Status} - {status.StatusInformation}");
                return false;
            }
            else if (status.Status != X509ChainStatusFlags.NoError)
            {
                LogCertificateWarning($"Non-critical chain status for {hostname}: {status.Status} - {status.StatusInformation}");
            }
        }
        
        // Validate chain length
        if (chain.ChainElements.Count > 10) // Reasonable maximum
        {
            LogCertificateError($"Certificate chain too long for {hostname}: {chain.ChainElements.Count} elements");
            return false;
        }
        
        return true;
    }
    
    private bool IsChainStatusCritical(X509ChainStatusFlags status)
    {
        var criticalStatuses = new[]
        {
            X509ChainStatusFlags.NotTimeValid,
            X509ChainStatusFlags.NotTimeNested,
            X509ChainStatusFlags.Revoked,
            X509ChainStatusFlags.NotSignatureValid,
            X509ChainStatusFlags.NotValidForUsage,
            X509ChainStatusFlags.UntrustedRoot,
            X509ChainStatusFlags.RevocationStatusUnknown,
            X509ChainStatusFlags.Cyclic,
            X509ChainStatusFlags.InvalidExtension,
            X509ChainStatusFlags.InvalidPolicyConstraints,
            X509ChainStatusFlags.InvalidBasicConstraints,
            X509ChainStatusFlags.InvalidNameConstraints,
            X509ChainStatusFlags.HasNotSupportedNameConstraint,
            X509ChainStatusFlags.HasNotDefinedNameConstraint,
            X509ChainStatusFlags.HasNotPermittedNameConstraint,
            X509ChainStatusFlags.HasExcludedNameConstraint
        };
        
        return criticalStatuses.Contains(status);
    }
    
    private bool ValidateCertificateDetails(X509Certificate2 certificate, string hostname)
    {
        // Check validity period
        var now = DateTime.Now;
        
        if (certificate.NotBefore > now)
        {
            LogCertificateError($"Certificate for {hostname} is not yet valid. Valid from: {certificate.NotBefore}");
            return false;
        }
        
        if (certificate.NotAfter < now)
        {
            LogCertificateError($"Certificate for {hostname} has expired. Valid until: {certificate.NotAfter}");
            return false;
        }
        
        // Check for upcoming expiration
        if (certificate.NotAfter - now < certificateExpirationWarningPeriod)
        {
            LogCertificateWarning($"Certificate for {hostname} expires soon: {certificate.NotAfter}");
        }
        
        // Validate key usage
        foreach (var extension in certificate.Extensions)
        {
            if (extension.Oid.Value == "2.5.29.15") // Key Usage
            {
                var keyUsage = extension as X509KeyUsageExtension;
                if (keyUsage != null && !keyUsage.KeyUsages.HasFlag(X509KeyUsageFlags.DigitalSignature))
                {
                    LogCertificateWarning($"Certificate for {hostname} missing DigitalSignature key usage");
                }
            }
            else if (extension.Oid.Value == "2.5.29.37") // Extended Key Usage
            {
                var extKeyUsage = extension as X509EnhancedKeyUsageExtension;
                if (extKeyUsage != null)
                {
                    var hasServerAuth = false;
                    foreach (var oid in extKeyUsage.EnhancedKeyUsages)
                    {
                        if (oid.Value == "1.3.6.1.5.5.7.3.1") // Server Authentication
                        {
                            hasServerAuth = true;
                            break;
                        }
                    }
                    
                    if (!hasServerAuth)
                    {
                        LogCertificateError($"Certificate for {hostname} missing Server Authentication extended key usage");
                        return false;
                    }
                }
            }
        }
        
        return true;
    }
    
    private bool ValidateCertificatePinning(X509Certificate2 certificate, X509Chain chain)
    {
        // Check leaf certificate
        if (IsCertificatePinned(certificate))
        {
            return true;
        }
        
        // Check intermediate certificates
        foreach (var element in chain.ChainElements)
        {
            if (IsCertificatePinned(element.Certificate))
            {
                return true;
            }
        }
        
        LogCertificateError("Certificate pinning validation failed - no matching pins found");
        return false;
    }
    
    private bool IsCertificatePinned(X509Certificate2 certificate)
    {
        try
        {
            // Calculate SHA-256 hash of public key
            var publicKeyBytes = certificate.GetPublicKey();
            using (var sha256 = System.Security.Cryptography.SHA256.Create())
            {
                var hash = sha256.ComputeHash(publicKeyBytes);
                var hashString = "sha256:" + Convert.ToBase64String(hash);
                
                return pinnedCertificateHashes.Contains(hashString);
            }
        }
        catch (Exception ex)
        {
            LogCertificateError($"Error calculating certificate hash: {ex.Message}");
            return false;
        }
    }
    
    private bool IsHostnameTrusted(string hostname)
    {
        if (trustedHostnames.Contains(hostname))
        {
            return true;
        }
        
        // Check wildcard matches
        return trustedHostnames.Any(trusted => 
            trusted.StartsWith("*.") && hostname.EndsWith(trusted.Substring(2)));
    }
    
    private void LogCertificateInfo(X509Certificate2 certificate, string hostname)
    {
        var info = new StringBuilder();
        info.AppendLine($"Certificate validation successful for {hostname}");
        info.AppendLine($"Subject: {certificate.Subject}");
        info.AppendLine($"Issuer: {certificate.Issuer}");
        info.AppendLine($"Valid from: {certificate.NotBefore}");
        info.AppendLine($"Valid until: {certificate.NotAfter}");
        info.AppendLine($"Thumbprint: {certificate.Thumbprint}");
        
        Console.WriteLine(info.ToString());
        // In production, use proper logging framework
    }
    
    private void LogCertificateError(string message)
    {
        Console.WriteLine($"[CERT ERROR] {DateTime.Now}: {message}");
        // In production, use proper logging framework and alerting
    }
    
    private void LogCertificateWarning(string message)
    {
        Console.WriteLine($"[CERT WARNING] {DateTime.Now}: {message}");
        // In production, use proper logging framework
    }
    
    public async Task<HttpClient> CreateSecureHttpClient()
    {
        var handler = new HttpClientHandler()
        {
            ServerCertificateCustomValidationCallback = ValidateCertificate
        };
        
        // Configure secure protocols
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
        
        return new HttpClient(handler);
    }
}

Detect This Vulnerability in Your Code

Sourcery automatically identifies improper ssl/tls certificate validation and many other security issues in your codebase.