"use strict";
/**
 * Certificate verification for mTLS authentication
 *
 * This module provides certificate revocation checking for client certificates
 * in mutual TLS (mTLS) connections. Supports both OCSP (Online Certificate
 * Status Protocol) and CRL (Certificate Revocation List) verification methods
 * with automatic method selection.
 *
 * Features:
 * - OCSP verification with caching
 * - CRL verification with caching
 * - CRL-first with OCSP fallback for optimal performance
 * - Background CRL refresh with exponential backoff
 * - Graceful degradation during network outages
 * - Ed25519/Ed448 certificate support
 *
 * Default behavior:
 * - Certificate verification: disabled (must be explicitly enabled)
 * - Verification approach: CRL-first (with OCSP fallback)
 * - CRL timeout: 10 seconds, cache TTL: 24 hours
 * - OCSP timeout: 5 seconds, cache TTL: 1 hour
 * - Failure mode: fail-closed (rejects connections if verification fails)
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyCertificate = verifyCertificate;
const logger_ts_1 = require("../../utility/logging/logger.js");
const verificationUtils_ts_1 = require("./verificationUtils.js");
const verificationConfig_ts_1 = require("./verificationConfig.js");
const ocspVerification_ts_1 = require("./ocspVerification.js");
const crlVerification_ts_1 = require("./crlVerification.js");
const logger = (0, logger_ts_1.loggerWithTag)('cert-verification');
/**
 * Verify certificate revocation status using OCSP and/or CRL
 * @param peerCertificate - Peer certificate object from TLS connection
 * @param mtlsConfig - The mTLS configuration from the request
 * @returns Promise resolving to verification result
 */
async function verifyCertificate(peerCertificate, mtlsConfig) {
    logger.debug?.(`verifyCertificate called for: ${peerCertificate.subject?.CN || 'unknown'}`);
    // Get the verification configuration from mtlsConfig (cached for performance)
    const config = (0, verificationConfig_ts_1.getCachedCertificateVerificationConfig)(mtlsConfig);
    // If config is false, verification is disabled
    if (config === false) {
        logger.debug?.('Certificate verification disabled');
        return { valid: true, status: 'disabled', method: 'disabled' };
    }
    // Extract certificate chain
    const certChain = (0, verificationUtils_ts_1.extractCertificateChain)(peerCertificate);
    logger.trace?.(`Certificate chain length: ${certChain.length}`);
    // Check if we have sufficient chain for verification (need certificate and issuer)
    if (certChain.length < 2 || !certChain[0].issuer) {
        logger.debug?.('Certificate chain insufficient for revocation checking - need certificate and issuer');
        return { valid: true, status: 'no-issuer-cert', method: 'disabled' };
    }
    // Extract certificate revocation URLs in single parse operation
    const certPem = (0, verificationUtils_ts_1.bufferToPem)(certChain[0].cert, 'CERTIFICATE');
    const { crlUrls, ocspUrls } = (0, verificationUtils_ts_1.extractRevocationUrls)(certPem);
    logger.debug?.(`Certificate extensions: CRL distribution points=${crlUrls.length}, OCSP URLs=${ocspUrls.length}`);
    // Try CRL first (can provide definitive results)
    if (crlUrls.length > 0) {
        if (config.crl.enabled) {
            try {
                logger.debug?.('Attempting CRL verification');
                const result = await (0, crlVerification_ts_1.verifyCRL)(certChain[0].cert, certChain[0].issuer, config.crl, crlUrls);
                // Return on definitive result (good or revoked)
                if (result.status === 'good' || result.status === 'revoked') {
                    logger.debug?.(`CRL verification result: ${result.status}`);
                    return result;
                }
                logger.debug?.(`CRL verification inconclusive: ${result.status}, trying OCSP fallback`);
            }
            catch (error) {
                logger.warn?.(`CRL verification failed: ${error}`);
            }
        }
        else {
            logger.debug?.('Skipping CRL - disabled in configuration');
        }
    }
    else {
        logger.debug?.('Skipping CRL - no distribution points in certificate');
    }
    // Fall back to OCSP if available (real-time status)
    if (ocspUrls.length > 0) {
        if (config.ocsp.enabled) {
            try {
                logger.debug?.('Attempting OCSP verification');
                const result = await (0, ocspVerification_ts_1.verifyOCSP)(certChain[0].cert, certChain[0].issuer, config.ocsp, ocspUrls);
                // Return on definitive result (good or revoked); fall through for inconclusive
                // so the failureMode logic below applies (same pattern as CRL)
                if (result.status === 'good' || result.status === 'revoked') {
                    logger.debug?.(`OCSP verification result: ${result.status}`);
                    return result;
                }
                logger.debug?.(`OCSP verification inconclusive: ${result.status}, applying failure mode`);
            }
            catch (error) {
                logger.warn?.(`OCSP verification failed: ${error}`);
            }
        }
        else {
            logger.debug?.('Skipping OCSP - disabled in configuration');
        }
    }
    else {
        logger.debug?.('Skipping OCSP - no responder URLs in certificate');
    }
    // All methods tried or skipped - determine failure handling
    // If both methods are explicitly disabled (not just unavailable), treat as disabled
    if (config.crl.enabled === false && config.ocsp.enabled === false) {
        logger.debug?.('Both CRL and OCSP disabled - verification disabled');
        return { valid: true, status: 'disabled', method: 'disabled' };
    }
    // Methods are enabled but unavailable - apply failure mode
    if (config.failureMode === 'fail-closed') {
        return { valid: false, status: 'no-verification-available', method: 'disabled' };
    }
    return { valid: true, status: 'verification-unavailable-allowed', method: 'disabled' };
}
//# sourceMappingURL=index.js.map